123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514 |
- package goja
- import (
- "fmt"
- "log"
- "math"
- "strconv"
- "sync"
- "sync/atomic"
- )
- const (
- maxInt = 1 << 53
- )
- type valueStack []Value
- type stash struct {
- values valueStack
- extraArgs valueStack
- names map[string]uint32
- obj objectImpl
- outer *stash
- }
- type context struct {
- prg *Program
- funcName string
- stash *stash
- pc, sb int
- args int
- }
- type iterStackItem struct {
- val Value
- f iterNextFunc
- }
- type ref interface {
- get() Value
- set(Value)
- refname() string
- }
- type stashRef struct {
- v *Value
- n string
- }
- func (r stashRef) get() Value {
- return *r.v
- }
- func (r *stashRef) set(v Value) {
- *r.v = v
- }
- func (r *stashRef) refname() string {
- return r.n
- }
- type objRef struct {
- base objectImpl
- name string
- strict bool
- }
- func (r *objRef) get() Value {
- return r.base.getStr(r.name)
- }
- func (r *objRef) set(v Value) {
- r.base.putStr(r.name, v, r.strict)
- }
- func (r *objRef) refname() string {
- return r.name
- }
- type unresolvedRef struct {
- runtime *Runtime
- name string
- }
- func (r *unresolvedRef) get() Value {
- r.runtime.throwReferenceError(r.name)
- panic("Unreachable")
- }
- func (r *unresolvedRef) set(v Value) {
- r.get()
- }
- func (r *unresolvedRef) refname() string {
- return r.name
- }
- type vm struct {
- r *Runtime
- prg *Program
- funcName string
- pc int
- stack valueStack
- sp, sb, args int
- stash *stash
- callStack []context
- iterStack []iterStackItem
- refStack []ref
- stashAllocs int
- halt bool
- interrupted uint32
- interruptVal interface{}
- interruptLock sync.Mutex
- }
- type instruction interface {
- exec(*vm)
- }
- func intToValue(i int64) Value {
- if i >= -maxInt && i <= maxInt {
- if i >= -128 && i <= 127 {
- return intCache[i+128]
- }
- return valueInt(i)
- }
- return valueFloat(float64(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 toInt(v Value) (int64, bool) {
- num := v.ToNumber()
- if i, ok := num.assertInt(); ok {
- return i, true
- }
- if f, ok := num.assertFloat(); ok {
- if i, ok := floatToInt(f); ok {
- return i, true
- }
- }
- return 0, false
- }
- func toIntIgnoreNegZero(v Value) (int64, bool) {
- num := v.ToNumber()
- if i, ok := num.assertInt(); ok {
- return i, true
- }
- if f, ok := num.assertFloat(); ok {
- if v == _negativeZero {
- return 0, true
- }
- if i, ok := floatToInt(f); ok {
- return i, true
- }
- }
- return 0, false
- }
- func (s *valueStack) expand(idx int) {
- if idx < len(*s) {
- return
- }
- if idx < cap(*s) {
- *s = (*s)[:idx+1]
- } else {
- n := make([]Value, idx+1, (idx+1)<<1)
- copy(n, *s)
- *s = n
- }
- }
- func (s *stash) put(name string, v Value) bool {
- if s.obj != nil {
- if found := s.obj.getStr(name); found != nil {
- s.obj.putStr(name, v, false)
- return true
- }
- return false
- } else {
- if idx, found := s.names[name]; found {
- s.values.expand(int(idx))
- s.values[idx] = v
- return true
- }
- return false
- }
- }
- func (s *stash) putByIdx(idx uint32, v Value) {
- if s.obj != nil {
- panic("Attempt to put by idx into an object scope")
- }
- s.values.expand(int(idx))
- s.values[idx] = v
- }
- func (s *stash) getByIdx(idx uint32) Value {
- if int(idx) < len(s.values) {
- return s.values[idx]
- }
- return _undefined
- }
- func (s *stash) getByName(name string, vm *vm) (v Value, exists bool) {
- if s.obj != nil {
- v = s.obj.getStr(name)
- if v == nil {
- return nil, false
- //return valueUnresolved{r: vm.r, ref: name}, false
- }
- return v, true
- }
- if idx, exists := s.names[name]; exists {
- return s.values[idx], true
- }
- return nil, false
- //return valueUnresolved{r: vm.r, ref: name}, false
- }
- func (s *stash) createBinding(name string) {
- if s.names == nil {
- s.names = make(map[string]uint32)
- }
- if _, exists := s.names[name]; !exists {
- s.names[name] = uint32(len(s.names))
- s.values = append(s.values, _undefined)
- }
- }
- func (s *stash) deleteBinding(name string) bool {
- if s.obj != nil {
- return s.obj.deleteStr(name, false)
- }
- if idx, found := s.names[name]; found {
- s.values[idx] = nil
- delete(s.names, name)
- return true
- }
- return false
- }
- func (vm *vm) newStash() {
- vm.stash = &stash{
- outer: vm.stash,
- }
- vm.stashAllocs++
- }
- func (vm *vm) init() {
- }
- func (vm *vm) run() {
- vm.halt = false
- interrupted := false
- for !vm.halt {
- if interrupted = atomic.LoadUint32(&vm.interrupted) != 0; interrupted {
- break
- }
- vm.prg.code[vm.pc].exec(vm)
- }
- if interrupted {
- vm.interruptLock.Lock()
- v := &InterruptedError{
- iface: vm.interruptVal,
- }
- atomic.StoreUint32(&vm.interrupted, 0)
- vm.interruptVal = nil
- vm.interruptLock.Unlock()
- panic(v)
- }
- }
- func (vm *vm) Interrupt(v interface{}) {
- vm.interruptLock.Lock()
- vm.interruptVal = v
- atomic.StoreUint32(&vm.interrupted, 1)
- vm.interruptLock.Unlock()
- }
- func (vm *vm) captureStack(stack []stackFrame, ctxOffset int) []stackFrame {
- // Unroll the context stack
- stack = append(stack, stackFrame{prg: vm.prg, pc: vm.pc, funcName: vm.funcName})
- for i := len(vm.callStack) - 1; i > ctxOffset-1; i-- {
- if vm.callStack[i].pc != -1 {
- stack = append(stack, stackFrame{prg: vm.callStack[i].prg, pc: vm.callStack[i].pc - 1, funcName: vm.callStack[i].funcName})
- }
- }
- return stack
- }
- func (vm *vm) try(f func()) (ex *Exception) {
- var ctx context
- vm.saveCtx(&ctx)
- ctxOffset := len(vm.callStack)
- sp := vm.sp
- iterLen := len(vm.iterStack)
- refLen := len(vm.refStack)
- defer func() {
- if x := recover(); x != nil {
- defer func() {
- vm.callStack = vm.callStack[:ctxOffset]
- vm.restoreCtx(&ctx)
- vm.sp = sp
- // Restore other stacks
- iterTail := vm.iterStack[iterLen:]
- for i, _ := range iterTail {
- iterTail[i] = iterStackItem{}
- }
- vm.iterStack = vm.iterStack[:iterLen]
- refTail := vm.refStack[refLen:]
- for i, _ := range refTail {
- refTail[i] = nil
- }
- vm.refStack = vm.refStack[:refLen]
- }()
- switch x1 := x.(type) {
- case Value:
- ex = &Exception{
- val: x1,
- }
- case *InterruptedError:
- x1.stack = vm.captureStack(x1.stack, ctxOffset)
- panic(x1)
- case *Exception:
- ex = 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))
- }
- ex.stack = vm.captureStack(ex.stack, ctxOffset)
- }
- }()
- f()
- return
- }
- func (vm *vm) runTry() (ex *Exception) {
- return vm.try(vm.run)
- }
- 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 = vm.prg
- ctx.funcName = vm.funcName
- ctx.stash = vm.stash
- ctx.pc = vm.pc
- ctx.sb = vm.sb
- ctx.args = vm.args
- }
- func (vm *vm) pushCtx() {
- /*
- vm.ctxStack = append(vm.ctxStack, context{
- prg: vm.prg,
- stash: vm.stash,
- pc: vm.pc,
- sb: vm.sb,
- args: vm.args,
- })*/
- vm.callStack = append(vm.callStack, context{})
- vm.saveCtx(&vm.callStack[len(vm.callStack)-1])
- }
- func (vm *vm) restoreCtx(ctx *context) {
- vm.prg = ctx.prg
- vm.funcName = ctx.funcName
- vm.pc = ctx.pc
- vm.stash = ctx.stash
- vm.sb = ctx.sb
- vm.args = ctx.args
- }
- func (vm *vm) popCtx() {
- l := len(vm.callStack) - 1
- vm.prg = vm.callStack[l].prg
- vm.callStack[l].prg = nil
- vm.funcName = vm.callStack[l].funcName
- vm.pc = vm.callStack[l].pc
- vm.stash = vm.callStack[l].stash
- vm.callStack[l].stash = nil
- vm.sb = vm.callStack[l].sb
- vm.args = vm.callStack[l].args
- vm.callStack = vm.callStack[:l]
- }
- func (r *Runtime) toObject(v Value, args ...interface{}) *Object {
- //r.checkResolveable(v)
- if obj, ok := v.(*Object); ok {
- return obj
- }
- if len(args) > 0 {
- r.typeErrorResult(true, args)
- } else {
- r.typeErrorResult(true, "Value is not an object: %s", v.ToString())
- }
- panic("Unreachable")
- }
- func (r *Runtime) toCallee(v Value) *Object {
- if obj, ok := v.(*Object); ok {
- return obj
- }
- switch unresolved := v.(type) {
- case valueUnresolved:
- unresolved.throw()
- panic("Unreachable")
- case memberUnresolved:
- r.typeErrorResult(true, "Object has no member '%s'", unresolved.ref)
- panic("Unreachable")
- }
- r.typeErrorResult(true, "Value is not an object: %s", v.ToString())
- panic("Unreachable")
- }
- type _newStash struct{}
- var newStash _newStash
- func (_newStash) exec(vm *vm) {
- vm.newStash()
- vm.pc++
- }
- type _noop struct{}
- var noop _noop
- func (_noop) exec(vm *vm) {
- vm.pc++
- }
- type loadVal uint32
- func (l loadVal) exec(vm *vm) {
- vm.push(vm.prg.values[l])
- vm.pc++
- }
- type loadVal1 uint32
- func (l *loadVal1) 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 _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 -- arg<-l-1>
- // l > 0 -- var<l-1>
- // l == 0 -- this
- if l < 0 {
- arg := int(-l)
- if arg > vm.args {
- vm.push(_undefined)
- } else {
- vm.push(vm.stack[vm.sb+arg])
- }
- } else if l > 0 {
- vm.push(vm.stack[vm.sb+vm.args+int(l)])
- } else {
- vm.push(vm.stack[vm.sb])
- }
- 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 -- arg<-l-1>
- // l > 0 -- var<l-1>
- // l == 0 -- this
- if s < 0 {
- vm.stack[vm.sb-s] = vm.stack[vm.sp-1]
- } else if s > 0 {
- vm.stack[vm.sb+vm.args+s] = vm.stack[vm.sp-1]
- } else {
- panic("Attempt to modify this")
- }
- vm.pc++
- }
- type storeStack int
- func (s storeStack) exec(vm *vm) {
- vm.storeStack(int(s))
- }
- type storeStackP int
- func (s storeStackP) exec(vm *vm) {
- vm.storeStack(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.self.toPrimitive()
- }
- if o, ok := right.(*Object); ok {
- right = o.self.toPrimitive()
- }
- var ret Value
- leftString, isLeftString := left.assertString()
- rightString, isRightString := right.assertString()
- if isLeftString || isRightString {
- if !isLeftString {
- leftString = left.ToString()
- }
- if !isRightString {
- rightString = right.ToString()
- }
- ret = leftString.concat(rightString)
- } else {
- if leftInt, ok := left.assertInt(); ok {
- if rightInt, ok := right.assertInt(); 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.assertInt(); ok {
- if right, ok := right.assertInt(); ok {
- result = intToValue(left - 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 := toInt(left); ok {
- if right, ok := toInt(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 _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 := toInt(left); ok {
- if rightInt, ok := toInt(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 := toInt(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 := toInt(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 := toInt(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 _halt struct{}
- var halt _halt
- func (_halt) exec(vm *vm) {
- vm.halt = true
- vm.pc++
- }
- type jump int32
- func (j jump) exec(vm *vm) {
- vm.pc += int(j)
- }
- type _setElem struct{}
- var setElem _setElem
- func (_setElem) exec(vm *vm) {
- obj := vm.r.toObject(vm.stack[vm.sp-3])
- propName := vm.stack[vm.sp-2]
- val := vm.stack[vm.sp-1]
- obj.self.put(propName, val, false)
- vm.sp -= 2
- vm.stack[vm.sp-1] = val
- vm.pc++
- }
- type _setElemStrict struct{}
- var setElemStrict _setElemStrict
- func (_setElemStrict) exec(vm *vm) {
- obj := vm.r.toObject(vm.stack[vm.sp-3])
- propName := vm.stack[vm.sp-2]
- val := vm.stack[vm.sp-1]
- obj.self.put(propName, val, true)
- vm.sp -= 2
- vm.stack[vm.sp-1] = val
- vm.pc++
- }
- type _deleteElem struct{}
- var deleteElem _deleteElem
- func (_deleteElem) exec(vm *vm) {
- obj := vm.r.toObject(vm.stack[vm.sp-2])
- propName := vm.stack[vm.sp-1]
- if !obj.self.hasProperty(propName) || obj.self.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.r.toObject(vm.stack[vm.sp-2])
- propName := vm.stack[vm.sp-1]
- obj.self.delete(propName, true)
- vm.stack[vm.sp-2] = valueTrue
- vm.sp--
- vm.pc++
- }
- type deleteProp string
- func (d deleteProp) exec(vm *vm) {
- obj := vm.r.toObject(vm.stack[vm.sp-1])
- if !obj.self.hasPropertyStr(string(d)) || obj.self.deleteStr(string(d), false) {
- vm.stack[vm.sp-1] = valueTrue
- } else {
- vm.stack[vm.sp-1] = valueFalse
- }
- vm.pc++
- }
- type deletePropStrict string
- func (d deletePropStrict) exec(vm *vm) {
- obj := vm.r.toObject(vm.stack[vm.sp-1])
- obj.self.deleteStr(string(d), true)
- vm.stack[vm.sp-1] = valueTrue
- vm.pc++
- }
- type setProp string
- func (p setProp) exec(vm *vm) {
- val := vm.stack[vm.sp-1]
- vm.r.toObject(vm.stack[vm.sp-2]).self.putStr(string(p), val, false)
- vm.stack[vm.sp-2] = val
- vm.sp--
- vm.pc++
- }
- type setPropStrict string
- func (p setPropStrict) exec(vm *vm) {
- obj := vm.stack[vm.sp-2]
- val := vm.stack[vm.sp-1]
- obj1 := vm.r.toObject(obj)
- obj1.self.putStr(string(p), val, true)
- vm.stack[vm.sp-2] = val
- vm.sp--
- vm.pc++
- }
- type setProp1 string
- func (p setProp1) exec(vm *vm) {
- vm.r.toObject(vm.stack[vm.sp-2]).self._putProp(string(p), vm.stack[vm.sp-1], true, true, true)
- vm.sp--
- vm.pc++
- }
- type _setProto struct{}
- var setProto _setProto
- func (_setProto) exec(vm *vm) {
- vm.r.toObject(vm.stack[vm.sp-2]).self.putStr("__proto__", vm.stack[vm.sp-1], true)
- vm.sp--
- vm.pc++
- }
- type setPropGetter string
- func (s setPropGetter) exec(vm *vm) {
- obj := vm.r.toObject(vm.stack[vm.sp-2])
- val := vm.stack[vm.sp-1]
- descr := propertyDescr{
- Getter: val,
- Configurable: FLAG_TRUE,
- Enumerable: FLAG_TRUE,
- }
- obj.self.defineOwnProperty(newStringValue(string(s)), descr, false)
- vm.sp--
- vm.pc++
- }
- type setPropSetter string
- func (s setPropSetter) exec(vm *vm) {
- obj := vm.r.toObject(vm.stack[vm.sp-2])
- val := vm.stack[vm.sp-1]
- descr := propertyDescr{
- Setter: val,
- Configurable: FLAG_TRUE,
- Enumerable: FLAG_TRUE,
- }
- obj.self.defineOwnProperty(newStringValue(string(s)), descr, false)
- vm.sp--
- vm.pc++
- }
- type getProp string
- func (g getProp) exec(vm *vm) {
- v := vm.stack[vm.sp-1]
- obj := v.baseObject(vm.r)
- if obj == nil {
- vm.r.typeErrorResult(true, "Cannot read property '%s' of undefined", g)
- }
- prop := obj.self.getPropStr(string(g))
- if prop1, ok := prop.(*valueProperty); ok {
- vm.stack[vm.sp-1] = prop1.get(v)
- } else {
- if prop == nil {
- prop = _undefined
- }
- vm.stack[vm.sp-1] = prop
- }
- vm.pc++
- }
- type getPropCallee string
- func (g getPropCallee) exec(vm *vm) {
- v := vm.stack[vm.sp-1]
- obj := v.baseObject(vm.r)
- if obj == nil {
- vm.r.typeErrorResult(true, "Cannot read property '%s' of undefined", g)
- }
- prop := obj.self.getPropStr(string(g))
- if prop1, ok := prop.(*valueProperty); ok {
- vm.stack[vm.sp-1] = prop1.get(v)
- } else {
- if prop == nil {
- prop = memberUnresolved{valueUnresolved{r: vm.r, ref: string(g)}}
- }
- vm.stack[vm.sp-1] = 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 := vm.stack[vm.sp-1]
- if obj == nil {
- vm.r.typeErrorResult(true, "Cannot read property '%s' of undefined", propName.String())
- }
- prop := obj.self.getProp(propName)
- if prop1, ok := prop.(*valueProperty); ok {
- vm.stack[vm.sp-2] = prop1.get(v)
- } else {
- if prop == nil {
- prop = _undefined
- }
- vm.stack[vm.sp-2] = prop
- }
- 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 := vm.stack[vm.sp-1]
- if obj == nil {
- vm.r.typeErrorResult(true, "Cannot read property '%s' of undefined", propName.String())
- panic("Unreachable")
- }
- prop := obj.self.getProp(propName)
- if prop1, ok := prop.(*valueProperty); ok {
- vm.stack[vm.sp-2] = prop1.get(v)
- } else {
- 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 _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, l)
- if l > 0 {
- copy(values, vm.stack[vm.sp-int(l):vm.sp])
- }
- obj := vm.r.newArrayValues(values)
- if l > 0 {
- vm.sp -= int(l) - 1
- vm.stack[vm.sp-1] = obj
- } else {
- vm.push(obj)
- }
- vm.pc++
- }
- type newRegexp struct {
- pattern regexpPattern
- src valueString
- global, ignoreCase, multiline bool
- }
- func (n *newRegexp) exec(vm *vm) {
- vm.push(vm.r.newRegExpp(n.pattern, n.src, n.global, n.ignoreCase, n.multiline, vm.r.global.RegExpPrototype))
- vm.pc++
- }
- func (vm *vm) setLocal(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.putByIdx(idx, v)
- vm.pc++
- }
- type setLocal uint32
- func (s setLocal) exec(vm *vm) {
- vm.setLocal(int(s))
- }
- type setLocalP uint32
- func (s setLocalP) exec(vm *vm) {
- vm.setLocal(int(s))
- vm.sp--
- }
- type setVar struct {
- name string
- idx uint32
- }
- func (s setVar) exec(vm *vm) {
- v := vm.peek()
- level := int(s.idx >> 24)
- idx := uint32(s.idx & 0x00FFFFFF)
- stash := vm.stash
- name := s.name
- for i := 0; i < level; i++ {
- if stash.put(name, v) {
- goto end
- }
- stash = stash.outer
- }
- if stash != nil {
- stash.putByIdx(idx, v)
- } else {
- vm.r.globalObject.self.putStr(name, v, false)
- }
- end:
- vm.pc++
- }
- type resolveVar1 string
- func (s resolveVar1) exec(vm *vm) {
- name := string(s)
- var ref ref
- for stash := vm.stash; stash != nil; stash = stash.outer {
- if stash.obj != nil {
- if stash.obj.hasPropertyStr(name) {
- ref = &objRef{
- base: stash.obj,
- name: name,
- }
- goto end
- }
- } else {
- if idx, exists := stash.names[name]; exists {
- ref = &stashRef{
- v: &stash.values[idx],
- }
- goto end
- }
- }
- }
- ref = &objRef{
- base: vm.r.globalObject.self,
- name: name,
- }
- end:
- vm.refStack = append(vm.refStack, ref)
- vm.pc++
- }
- type deleteVar string
- func (d deleteVar) exec(vm *vm) {
- name := string(d)
- ret := true
- for stash := vm.stash; stash != nil; stash = stash.outer {
- if stash.obj != nil {
- if stash.obj.hasPropertyStr(name) {
- ret = stash.obj.deleteStr(name, false)
- goto end
- }
- } else {
- if _, exists := stash.names[name]; exists {
- 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 string
- func (d deleteGlobal) exec(vm *vm) {
- name := string(d)
- var ret bool
- if vm.r.globalObject.self.hasPropertyStr(name) {
- ret = vm.r.globalObject.self.deleteStr(name, false)
- } else {
- ret = true
- }
- if ret {
- vm.push(valueTrue)
- } else {
- vm.push(valueFalse)
- }
- vm.pc++
- }
- type resolveVar1Strict string
- func (s resolveVar1Strict) exec(vm *vm) {
- name := string(s)
- var ref ref
- for stash := vm.stash; stash != nil; stash = stash.outer {
- if stash.obj != nil {
- if stash.obj.hasPropertyStr(name) {
- ref = &objRef{
- base: stash.obj,
- name: name,
- strict: true,
- }
- goto end
- }
- } else {
- if idx, exists := stash.names[name]; exists {
- ref = &stashRef{
- v: &stash.values[idx],
- }
- goto end
- }
- }
- }
- if vm.r.globalObject.self.hasPropertyStr(name) {
- ref = &objRef{
- base: vm.r.globalObject.self,
- name: name,
- strict: true,
- }
- goto end
- }
- ref = &unresolvedRef{
- runtime: vm.r,
- name: string(s),
- }
- end:
- vm.refStack = append(vm.refStack, ref)
- vm.pc++
- }
- type setGlobal string
- func (s setGlobal) exec(vm *vm) {
- v := vm.peek()
- vm.r.globalObject.self.putStr(string(s), v, false)
- vm.pc++
- }
- type setVarStrict struct {
- name string
- idx uint32
- }
- func (s setVarStrict) exec(vm *vm) {
- v := vm.peek()
- level := int(s.idx >> 24)
- idx := uint32(s.idx & 0x00FFFFFF)
- stash := vm.stash
- name := s.name
- for i := 0; i < level; i++ {
- if stash.put(name, v) {
- goto end
- }
- stash = stash.outer
- }
- if stash != nil {
- stash.putByIdx(idx, v)
- } else {
- o := vm.r.globalObject.self
- if o.hasOwnPropertyStr(name) {
- o.putStr(name, v, true)
- } else {
- vm.r.throwReferenceError(name)
- }
- }
- end:
- vm.pc++
- }
- type setVar1Strict string
- func (s setVar1Strict) exec(vm *vm) {
- v := vm.peek()
- var o objectImpl
- name := string(s)
- for stash := vm.stash; stash != nil; stash = stash.outer {
- if stash.put(name, v) {
- goto end
- }
- }
- o = vm.r.globalObject.self
- if o.hasOwnPropertyStr(name) {
- o.putStr(name, v, true)
- } else {
- vm.r.throwReferenceError(name)
- }
- end:
- vm.pc++
- }
- type setGlobalStrict string
- func (s setGlobalStrict) exec(vm *vm) {
- v := vm.peek()
- name := string(s)
- o := vm.r.globalObject.self
- if o.hasOwnPropertyStr(name) {
- o.putStr(name, v, true)
- } else {
- vm.r.throwReferenceError(name)
- }
- vm.pc++
- }
- type getLocal uint32
- func (g getLocal) 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(stash.getByIdx(idx))
- vm.pc++
- }
- type getVar struct {
- name string
- idx uint32
- ref bool
- }
- func (g getVar) exec(vm *vm) {
- level := int(g.idx >> 24)
- idx := uint32(g.idx & 0x00FFFFFF)
- stash := vm.stash
- name := g.name
- for i := 0; i < level; i++ {
- if v, found := stash.getByName(name, vm); found {
- vm.push(v)
- goto end
- }
- stash = stash.outer
- }
- if stash != nil {
- vm.push(stash.getByIdx(idx))
- } else {
- v := vm.r.globalObject.self.getStr(name)
- if v == nil {
- if g.ref {
- v = valueUnresolved{r: vm.r, ref: name}
- } else {
- vm.r.throwReferenceError(name)
- }
- }
- vm.push(v)
- }
- end:
- vm.pc++
- }
- type resolveVar struct {
- name string
- idx uint32
- strict bool
- }
- func (r resolveVar) exec(vm *vm) {
- level := int(r.idx >> 24)
- idx := uint32(r.idx & 0x00FFFFFF)
- stash := vm.stash
- var ref ref
- for i := 0; i < level; i++ {
- if stash.obj != nil {
- if stash.obj.hasPropertyStr(r.name) {
- ref = &objRef{
- base: stash.obj,
- name: r.name,
- strict: r.strict,
- }
- goto end
- }
- } else {
- if idx, exists := stash.names[r.name]; exists {
- ref = &stashRef{
- v: &stash.values[idx],
- }
- goto end
- }
- }
- stash = stash.outer
- }
- if stash != nil {
- ref = &stashRef{
- v: &stash.values[idx],
- }
- goto end
- } /*else {
- if vm.r.globalObject.self.hasProperty(nameVal) {
- ref = &objRef{
- base: vm.r.globalObject.self,
- name: r.name,
- }
- goto end
- }
- } */
- ref = &unresolvedRef{
- runtime: vm.r,
- name: r.name,
- }
- 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.r.throwReferenceError(ref.refname())
- panic("Unreachable")
- }
- 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 getVar1 string
- func (n getVar1) exec(vm *vm) {
- name := string(n)
- var val Value
- for stash := vm.stash; stash != nil; stash = stash.outer {
- if v, exists := stash.getByName(name, vm); exists {
- val = v
- break
- }
- }
- if val == nil {
- val = vm.r.globalObject.self.getStr(name)
- if val == nil {
- vm.r.throwReferenceError(name)
- }
- }
- vm.push(val)
- vm.pc++
- }
- type getVar1Callee string
- func (n getVar1Callee) exec(vm *vm) {
- name := string(n)
- var val Value
- for stash := vm.stash; stash != nil; stash = stash.outer {
- if v, exists := stash.getByName(name, vm); exists {
- val = v
- break
- }
- }
- if val == nil {
- val = vm.r.globalObject.self.getStr(name)
- if val == nil {
- val = valueUnresolved{r: vm.r, ref: name}
- }
- }
- vm.push(val)
- vm.pc++
- }
- type _pop struct{}
- var pop _pop
- func (_pop) exec(vm *vm) {
- vm.sp--
- vm.pc++
- }
- type _swap struct{}
- var swap _swap
- func (_swap) exec(vm *vm) {
- vm.stack[vm.sp-1], vm.stack[vm.sp-2] = vm.stack[vm.sp-2], vm.stack[vm.sp-1]
- 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.assertString(); ok {
- var this Value
- if vm.sb != 0 {
- this = vm.stack[vm.sb]
- } else {
- this = vm.r.globalObject
- }
- ret := vm.r.eval(src.String(), true, strict, this)
- 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 _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++
- }
- 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.r.toCallee(v)
- repeat:
- switch f := obj.self.(type) {
- case *funcObject:
- vm.pc++
- vm.pushCtx()
- vm.args = n
- vm.prg = f.prg
- vm.stash = f.stash
- vm.pc = 0
- vm.stack[vm.sp-n-1], vm.stack[vm.sp-n-2] = vm.stack[vm.sp-n-2], vm.stack[vm.sp-n-1]
- return
- case *nativeFuncObject:
- vm._nativeCall(f, n)
- case *boundFuncObject:
- vm._nativeCall(&f.nativeFuncObject, n)
- case *lazyObject:
- obj.self = f.create(obj)
- goto repeat
- default:
- vm.r.typeErrorResult(true, "Not a function: %s", obj.ToString())
- }
- }
- func (vm *vm) _nativeCall(f *nativeFuncObject, n int) {
- if f.f != nil {
- vm.pushCtx()
- vm.prg = nil
- vm.funcName = f.nameProp.get(nil).String()
- ret := f.f(FunctionCall{
- Arguments: vm.stack[vm.sp-n : vm.sp],
- This: vm.stack[vm.sp-n-2],
- })
- if ret == nil {
- ret = _undefined
- }
- vm.stack[vm.sp-n-2] = ret
- vm.popCtx()
- } else {
- vm.stack[vm.sp-n-2] = _undefined
- }
- vm.sp -= n + 1
- vm.pc++
- }
- func (vm *vm) clearStack() {
- stackTail := vm.stack[vm.sp:]
- for i := range stackTail {
- stackTail[i] = nil
- }
- vm.stack = vm.stack[:vm.sp]
- }
- type enterFunc uint32
- func (e enterFunc) exec(vm *vm) {
- // Input stack:
- //
- // callee
- // this
- // arg0
- // ...
- // argN
- // <- sp
- // Output stack:
- //
- // this <- sb
- // <- sp
- vm.newStash()
- offset := vm.args - int(e)
- vm.stash.values = make([]Value, e)
- if offset > 0 {
- copy(vm.stash.values, vm.stack[vm.sp-vm.args:])
- vm.stash.extraArgs = make([]Value, offset)
- copy(vm.stash.extraArgs, vm.stack[vm.sp-offset:])
- } else {
- copy(vm.stash.values, vm.stack[vm.sp-vm.args:])
- vv := vm.stash.values[vm.args:]
- for i, _ := range vv {
- vv[i] = _undefined
- }
- }
- vm.sp -= vm.args
- vm.sb = vm.sp - 1
- vm.pc++
- }
- type _ret struct{}
- var ret _ret
- func (_ret) exec(vm *vm) {
- // callee -3
- // this -2
- // retval -1
- vm.stack[vm.sp-3] = vm.stack[vm.sp-1]
- vm.sp -= 2
- vm.popCtx()
- if vm.pc < 0 {
- vm.halt = true
- }
- }
- type enterFuncStashless struct {
- stackSize uint32
- args uint32
- }
- func (e enterFuncStashless) exec(vm *vm) {
- vm.sb = vm.sp - vm.args - 1
- var ss int
- d := int(e.args) - vm.args
- if d > 0 {
- ss = int(e.stackSize) + d
- vm.args = int(e.args)
- } else {
- ss = int(e.stackSize)
- }
- sp := vm.sp
- if ss > 0 {
- vm.sp += int(ss)
- vm.stack.expand(vm.sp)
- s := vm.stack[sp:vm.sp]
- for i, _ := range s {
- s[i] = _undefined
- }
- }
- vm.pc++
- }
- type _retStashless struct{}
- var retStashless _retStashless
- func (_retStashless) exec(vm *vm) {
- retval := vm.stack[vm.sp-1]
- vm.sp = vm.sb
- vm.stack[vm.sp-1] = retval
- vm.popCtx()
- if vm.pc < 0 {
- vm.halt = true
- }
- }
- type newFunc struct {
- prg *Program
- name string
- length uint32
- strict bool
- srcStart, srcEnd uint32
- }
- func (n *newFunc) exec(vm *vm) {
- obj := vm.r.newFunc(n.name, int(n.length), n.strict)
- obj.prg = n.prg
- obj.stash = vm.stash
- obj.src = n.prg.src.src[n.srcStart:n.srcEnd]
- vm.push(obj.val)
- vm.pc++
- }
- type bindName string
- func (d bindName) exec(vm *vm) {
- if vm.stash != nil {
- vm.stash.createBinding(string(d))
- } else {
- vm.r.globalObject.self._putProp(string(d), _undefined, true, true, false)
- }
- 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.pc++
- }
- }
- type jneq1 int32
- func (j jneq1) exec(vm *vm) {
- if !vm.stack[vm.sp-1].ToBoolean() {
- vm.pc += int(j)
- } else {
- vm.pc++
- }
- }
- 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.self.toPrimitiveNumber()
- }
- return v
- }
- func cmp(px, py Value) Value {
- var ret bool
- var nx, ny float64
- if xs, ok := px.assertString(); ok {
- if ys, ok := py.assertString(); ok {
- ret = xs.compareTo(ys) < 0
- goto end
- }
- }
- if xi, ok := px.assertInt(); ok {
- if yi, ok := py.assertInt(); 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 right.self.hasInstance(left) {
- 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.self.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
- dynamic bool
- }
- func (t try) exec(vm *vm) {
- o := vm.pc
- vm.pc++
- ex := vm.runTry()
- if ex != nil && t.catchOffset > 0 {
- // run the catch block (in try)
- vm.pc = o + int(t.catchOffset)
- // TODO: if ex.val is an Error, set the stack property
- if t.dynamic {
- vm.newStash()
- vm.stash.putByIdx(0, ex.val)
- } else {
- vm.push(ex.val)
- }
- ex = vm.runTry()
- if t.dynamic {
- vm.stash = vm.stash.outer
- }
- }
- if t.finallyOffset > 0 {
- pc := vm.pc
- // Run finally
- vm.pc = o + int(t.finallyOffset)
- vm.run()
- if vm.prg.code[vm.pc] == retFinally {
- vm.pc = pc
- } else {
- // break or continue out of finally, dropping exception
- ex = nil
- }
- }
- vm.halt = false
- if ex != nil {
- panic(ex)
- }
- }
- type _retFinally struct{}
- var retFinally _retFinally
- func (_retFinally) exec(vm *vm) {
- vm.pc++
- }
- type enterCatch string
- func (varName enterCatch) exec(vm *vm) {
- vm.stash.names = map[string]uint32{
- string(varName): 0,
- }
- vm.pc++
- }
- type _throw struct{}
- var throw _throw
- func (_throw) exec(vm *vm) {
- panic(vm.stack[vm.sp-1])
- }
- type _new uint32
- func (n _new) exec(vm *vm) {
- obj := vm.r.toObject(vm.stack[vm.sp-1-int(n)])
- repeat:
- switch f := obj.self.(type) {
- case *funcObject:
- args := make([]Value, n)
- copy(args, vm.stack[vm.sp-int(n):])
- vm.sp -= int(n)
- vm.stack[vm.sp-1] = f.construct(args)
- case *nativeFuncObject:
- vm._nativeNew(f, int(n))
- case *boundFuncObject:
- vm._nativeNew(&f.nativeFuncObject, int(n))
- case *lazyObject:
- obj.self = f.create(obj)
- goto repeat
- default:
- vm.r.typeErrorResult(true, "Not a constructor")
- }
- vm.pc++
- }
- func (vm *vm) _nativeNew(f *nativeFuncObject, n int) {
- if f.construct != nil {
- args := make([]Value, n)
- copy(args, vm.stack[vm.sp-n:])
- vm.sp -= n
- vm.stack[vm.sp-1] = f.construct(args)
- } else {
- vm.r.typeErrorResult(true, "Not a constructor")
- }
- }
- 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:
- repeat:
- switch s := v.self.(type) {
- case *funcObject, *nativeFuncObject, *boundFuncObject:
- r = stringFunction
- case *lazyObject:
- v.self = s.create(v)
- goto repeat
- default:
- r = stringObjectC
- }
- case valueBool:
- r = stringBoolean
- case valueString:
- r = stringString
- case valueInt, valueFloat:
- r = stringNumber
- default:
- panic(fmt.Errorf("Unknown type: %T", v))
- }
- vm.stack[vm.sp-1] = r
- vm.pc++
- }
- type createArgs uint32
- func (formalArgs createArgs) 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(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(strconv.Itoa(i), v)
- i++
- }
- args._putProp("callee", vm.stack[vm.sb-1], true, false, true)
- vm.push(v)
- vm.pc++
- }
- type createArgsStrict uint32
- func (formalArgs createArgsStrict) 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(strconv.Itoa(i), v)
- i++
- }
- for _, v := range vm.stash.extraArgs {
- args._put(strconv.Itoa(i), v)
- i++
- }
- args._putProp("length", intToValue(int64(vm.args)), true, false, true)
- args._put("callee", vm.r.global.throwerProperty)
- args._put("caller", vm.r.global.throwerProperty)
- 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).self
- 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: v.ToObject(vm.r).self.enumerate(false, true)})
- }
- 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 = newStringValue(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++
- }
|