github.com/coyove/nj@v0.0.0-20221110084952-c7f8db1065c3/bas/eval.go (about)

     1  package bas
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"math"
     7  	"strings"
     8  	"unicode/utf8"
     9  	"unsafe"
    10  
    11  	"github.com/coyove/nj/internal"
    12  	"github.com/coyove/nj/typ"
    13  )
    14  
    15  type Stacktrace struct {
    16  	Cursor      uint32
    17  	StackOffset uint32
    18  	Callable    *Object
    19  }
    20  
    21  func (r *Stacktrace) sourceLine() (src uint32) {
    22  	posv := r.Callable.fun.codeSeg.Pos
    23  	lastLine := uint32(math.MaxUint32)
    24  	cursor := r.Cursor - 1
    25  	if posv.Len() > 0 {
    26  		_, op, line := posv.Read(0)
    27  		for cursor > op && posv.Len() > 0 {
    28  			op, line = posv.Pop()
    29  			// fmt.Println(r.Callable.fun.name, cursor, op, line)
    30  		}
    31  		if cursor <= op {
    32  			return line
    33  		}
    34  		lastLine = line
    35  	}
    36  	return lastLine
    37  }
    38  
    39  // ExecError represents the runtime error/panic.
    40  type ExecError struct {
    41  	fatal  bool
    42  	root   interface{}
    43  	stacks []Stacktrace
    44  }
    45  
    46  func (e *ExecError) IsPanic() bool {
    47  	return e.fatal
    48  }
    49  
    50  func (e *ExecError) GetCause() interface{} {
    51  	if e == nil {
    52  		return nil
    53  	}
    54  	return e.root
    55  }
    56  
    57  func (e *ExecError) Error() string {
    58  	msg := bytes.Buffer{}
    59  	e.printError(&msg, 0)
    60  	return msg.String()
    61  }
    62  
    63  func (e *ExecError) printError(msg *bytes.Buffer, idx int) {
    64  	if ee, ok := e.root.(*ExecError); ok {
    65  		ee.printError(msg, idx+1)
    66  	} else if ee, ok := e.root.(Value); ok && ee.IsError() {
    67  		ee.Error().printError(msg, idx+1)
    68  	} else {
    69  		fmt.Fprint(msg, e.root)
    70  	}
    71  	msg.WriteByte('\n')
    72  
    73  	if e.fatal {
    74  		msg.WriteString("fatal ")
    75  	}
    76  
    77  	if idx == 0 {
    78  		msg.WriteString("stacktrace:\n")
    79  	} else {
    80  		msg.WriteString(fmt.Sprintf("stacktrace %d:\n", idx))
    81  	}
    82  
    83  	if len(e.stacks) == 0 {
    84  		msg.WriteString("none\n")
    85  	} else {
    86  		for i := len(e.stacks) - 1; i >= 0; i-- {
    87  			r := e.stacks[i]
    88  			if r.Callable.fun.native != nil {
    89  				msg.WriteString(fmt.Sprintf("%s (native function)\n\t<native code>\n", r.Callable.fun.name))
    90  			} else {
    91  				ln := r.sourceLine()
    92  				msg.WriteString(fmt.Sprintf("%s at %s:%d (i%d)",
    93  					r.Callable.fun.name,
    94  					r.Callable.fun.codeSeg.Pos.Name,
    95  					ln,
    96  					r.Cursor-1, // the recorded cursor was advanced by 1 already
    97  				))
    98  				msg.WriteString("\n\t")
    99  				line, ok := internal.LineOf(r.Callable.fun.top.Source, int(ln))
   100  				if ok {
   101  					msg.WriteString(strings.TrimSpace(line))
   102  				} else {
   103  					msg.WriteString("<unknown source>")
   104  				}
   105  				msg.WriteString("\n")
   106  			}
   107  		}
   108  	}
   109  	msg.Truncate(msg.Len() - 1)
   110  }
   111  
   112  func relayPanic(onPanic func() []Stacktrace) {
   113  	if r := recover(); r != nil {
   114  		if re, ok := r.(*ExecError); ok {
   115  			panic(re)
   116  		}
   117  
   118  		e := &ExecError{}
   119  		e.fatal = true
   120  		e.root = r
   121  		e.stacks = append([]Stacktrace{}, onPanic()...)
   122  		panic(e)
   123  	}
   124  }
   125  
   126  func internalExecCursorLoop(env Env, K *Object, retStack []Stacktrace) Value {
   127  	stackEnv := env
   128  	stackEnv.stackOffset = uint32(len(*env.stack))
   129  
   130  	var cursor uint32
   131  	retStackStartSize := len(retStack)
   132  
   133  	defer relayPanic(func() []Stacktrace {
   134  		retStack = append(retStack, Stacktrace{
   135  			Cursor:      cursor,
   136  			Callable:    K,
   137  			StackOffset: env.stackOffset,
   138  		})
   139  		if stackEnv.runtime.stack0.Callable != nil {
   140  			retStack = append(retStack, stackEnv.runtime.stack0)
   141  		}
   142  		return retStack
   143  	})
   144  
   145  	code := K.fun.codeSeg.CodePtr()
   146  	for {
   147  		v := (*typ.Inst)(unsafe.Pointer(code + typ.InstSize*uintptr(cursor)))
   148  		opa, opb := v.A, v.B
   149  		cursor++
   150  
   151  		switch v.Opcode {
   152  		case typ.OpSet:
   153  			env._set(opa, env._get(opb))
   154  		case typ.OpInc:
   155  			va := env._ref(opa)
   156  			if vb := env._get(opb); va.IsInt64() && vb.IsInt64() {
   157  				*va = Int64(va.UnsafeInt64() + vb.UnsafeInt64())
   158  			} else if va.IsNumber() && vb.IsNumber() {
   159  				*va = Float64(va.Float64() + vb.Float64())
   160  			} else if vat := va.Type(); vat == typ.String && vb.Type() == typ.String {
   161  				*va = Str(va.Str() + vb.Str())
   162  			} else if vat == typ.Native {
   163  				va.Native().Append(vb)
   164  			} else {
   165  				internal.Panic("inc "+errNeedNumbersOrStrings, va.simple(), vb.simple())
   166  			}
   167  			env.A = *va
   168  			cursor = uint32(int32(cursor) + int32(int16(v.C)))
   169  		case typ.OpNext:
   170  			va, vb := env._get(opa), env._get(opb)
   171  			switch va.Type() {
   172  			case typ.Nil:
   173  				env.A = Nil
   174  			case typ.Native:
   175  				env.A = va.Native().internalNext(vb)
   176  			case typ.Object:
   177  				env.A = va.Object().internalNext(vb)
   178  			case typ.String:
   179  				idx := 0
   180  				if vb != Nil {
   181  					idx = vb.Native().Get(0).Int()
   182  				} else {
   183  					vb = Array(Nil, Nil)
   184  				}
   185  				if r, sz := utf8.DecodeRuneInString(va.Str()[idx:]); sz == 0 {
   186  					vb.Native().Set(0, Nil)
   187  					vb.Native().Set(1, Nil)
   188  				} else {
   189  					vb.Native().Set(0, Int(idx+sz))
   190  					vb.Native().Set(1, Int(int(r)))
   191  				}
   192  				env.A = vb
   193  			default:
   194  				internal.Panic("can't iterate over %v", va.simple())
   195  			}
   196  		case typ.OpLen:
   197  			env.A = Int(env._get(opa).Len())
   198  		case typ.OpExt:
   199  			switch v.OpcodeExt {
   200  			case typ.OpExtInc16:
   201  				va := env._ref(opa)
   202  				if va.IsInt64() {
   203  					*va = Int64(va.UnsafeInt64() + int64(int16(opb)))
   204  				} else if va.IsNumber() {
   205  					*va = Float64(va.Float64() + float64(int16(opb)))
   206  				} else if va.Type() == typ.Native {
   207  					va.Native().Append(Int(int(int16(opb))))
   208  				} else {
   209  					internal.Panic("inc "+errNeedNumbers, va.simple(), int16(opb))
   210  				}
   211  				env.A = *va
   212  				cursor = uint32(int32(cursor) + int32(int16(v.C)))
   213  			case typ.OpExtLess16:
   214  				if va := env._ref(opa); va.IsInt64() {
   215  					env.A = Bool(va.UnsafeInt64() < int64(int16(opb)))
   216  				} else if va.IsNumber() {
   217  					env.A = Bool(va.UnsafeFloat64() < float64(int16(opb)))
   218  				} else {
   219  					internal.Panic("comparison "+errNeedNumbers, va.simple(), int16(opb))
   220  				}
   221  			case typ.OpExtAdd16:
   222  				if va := env._ref(opa); va.IsInt64() {
   223  					env.A = Int64(va.UnsafeInt64() + int64(int16(opb)))
   224  				} else if va.IsNumber() {
   225  					env.A = Float64(va.UnsafeFloat64() + float64(int16(opb)))
   226  				} else if va.Type() == typ.Native {
   227  					va.Native().Append(Int(int(int16(opb))))
   228  					env.A = *va
   229  				} else {
   230  					internal.Panic("add "+errNeedNumbers, va.simple(), int16(opb))
   231  				}
   232  			case typ.OpExtRSub16:
   233  				if va := env._ref(opa); va.IsInt64() {
   234  					env.A = Int64(int64(int16(opb)) - va.UnsafeInt64())
   235  				} else if va.IsNumber() {
   236  					env.A = Float64(float64(int16(opb)) - va.UnsafeFloat64())
   237  				} else {
   238  					internal.Panic("sub "+errNeedNumbers, va.simple(), int16(opb))
   239  				}
   240  			case typ.OpExtGreat16:
   241  				if va := env._ref(opa); va.IsInt64() {
   242  					env.A = Bool(va.UnsafeInt64() > int64(int16(opb)))
   243  				} else if va.IsNumber() {
   244  					env.A = Bool(va.UnsafeFloat64() > float64(int16(opb)))
   245  				} else {
   246  					internal.Panic("comparison "+errNeedNumbers, va.simple(), int16(opb))
   247  				}
   248  			case typ.OpExtNeq16:
   249  				env.A = Bool(env._get(opa) != Int64(int64(int16(opb))))
   250  			case typ.OpExtEq16:
   251  				env.A = Bool(env._get(opa) == Int64(int64(int16(opb))))
   252  			case typ.OpExtStore16:
   253  				subject, v := env._ref(opa), env._get(v.C)
   254  				if st := subject.Type(); st == typ.Native {
   255  					subject.Native().Set(int(int16(opb)), v)
   256  				} else if st == typ.Object {
   257  					subject.Object().Set(Int(int(int16(opb))), v)
   258  				} else {
   259  					internal.Panic("can't index %v using %v", subject.simple(), int16(opb))
   260  				}
   261  				env.A = v
   262  			case typ.OpExtLoad16:
   263  				a := env._ref(opa)
   264  				if at := a.Type(); at == typ.Native {
   265  					env.A = a.Native().Get(int(int16(opb)))
   266  				} else if at == typ.String {
   267  					env.A = Int64(int64(a.Str()[int16(opb)]))
   268  				} else if at == typ.Object {
   269  					env.A = a.Object().Get(Int(int(int16(opb))))
   270  				} else {
   271  					env.A = Nil
   272  				}
   273  				if v.C != typ.RegA {
   274  					env._set(v.C, env.A)
   275  				}
   276  			case typ.OpExtBitAnd:
   277  				va, vb := env._ref(opa), env._ref(opb)
   278  				if va.Type() == typ.Native && vb.Type() == typ.Native {
   279  					va.Native().Concat(vb.Native())
   280  					env.A = *va
   281  				} else {
   282  					bassertTwoInts("and", va, vb)
   283  					env.A = Int64(va.Int64() & vb.Int64())
   284  				}
   285  			case typ.OpExtBitOr:
   286  				va, vb := env._ref(opa), env._ref(opb)
   287  				bassertTwoInts("or", va, vb)
   288  				env.A = Int64(va.Int64() | vb.Int64())
   289  			case typ.OpExtBitXor:
   290  				va, vb := env._ref(opa), env._ref(opb)
   291  				bassertTwoInts("xor", va, vb)
   292  				env.A = Int64(va.Int64() ^ vb.Int64())
   293  			case typ.OpExtBitLsh:
   294  				va, vb := env._ref(opa), env._ref(opb)
   295  				bassertTwoInts("lsh", va, vb)
   296  				env.A = Int64(va.Int64() << vb.Int64())
   297  			case typ.OpExtBitRsh:
   298  				va, vb := env._ref(opa), env._ref(opb)
   299  				bassertTwoInts("rsh", va, vb)
   300  				env.A = Int64(va.Int64() >> vb.Int64())
   301  			case typ.OpExtBitURsh:
   302  				va, vb := env._ref(opa), env._ref(opb)
   303  				bassertTwoInts("ursh", va, vb)
   304  				env.A = Int64(int64(uint64(va.Int64()) >> vb.Int64()))
   305  			case typ.OpExtBitAnd16:
   306  				va := env._get(opa)
   307  				bassertOneInt("and", va)
   308  				env.A = Int64(va.Int64() & int64(int16(opb)))
   309  			case typ.OpExtBitOr16:
   310  				va := env._get(opa)
   311  				bassertOneInt("or", va)
   312  				env.A = Int64(va.Int64() | int64(int16(opb)))
   313  			case typ.OpExtBitXor16:
   314  				va := env._get(opa)
   315  				bassertOneInt("xor", va)
   316  				env.A = Int64(va.Int64() ^ int64(int16(opb)))
   317  			case typ.OpExtBitLsh16:
   318  				va := env._get(opa)
   319  				bassertOneInt("lsh", va)
   320  				env.A = Int64(va.Int64() << int64(int16(opb)))
   321  			case typ.OpExtBitRsh16:
   322  				va := env._get(opa)
   323  				bassertOneInt("rsh", va)
   324  				env.A = Int64(va.Int64() >> int64(int16(opb)))
   325  			case typ.OpExtBitURsh16:
   326  				va := env._get(opa)
   327  				bassertOneInt("uRsh", va)
   328  				env.A = Int64(int64(uint64(va.Int64()) >> int64(int16(opb))))
   329  			}
   330  		case typ.OpAdd:
   331  			if va, vb := env._ref(opa), env._ref(opb); va.IsInt64() && vb.IsInt64() {
   332  				env.A = Int64(va.UnsafeInt64() + vb.UnsafeInt64())
   333  			} else if va.IsNumber() && vb.IsNumber() {
   334  				env.A = Float64(va.Float64() + vb.Float64())
   335  			} else if vat, vbt := va.Type(), vb.Type(); vat == typ.String && vbt == typ.String {
   336  				env.A = Str(va.Str() + vb.Str())
   337  			} else if vat == typ.Native {
   338  				va.Native().Append(*vb)
   339  				env.A = *va
   340  			} else {
   341  				internal.Panic("add "+errNeedNumbersOrStrings, va.simple(), vb.simple())
   342  			}
   343  		case typ.OpSub:
   344  			if va, vb := env._ref(opa), env._ref(opb); va.IsInt64() && vb.IsInt64() {
   345  				env.A = Int64(va.UnsafeInt64() - vb.UnsafeInt64())
   346  			} else if va.IsNumber() && vb.IsNumber() {
   347  				env.A = Float64(va.Float64() - vb.Float64())
   348  			} else if va.IsObject() {
   349  				env.A = va.Object().Delete(*vb)
   350  			} else {
   351  				internal.Panic("sub "+errNeedNumbers, va.simple(), vb.simple())
   352  			}
   353  		case typ.OpMul:
   354  			if va, vb := env._ref(opa), env._ref(opb); va.IsInt64() && vb.IsInt64() {
   355  				env.A = Int64(va.UnsafeInt64() * vb.UnsafeInt64())
   356  			} else if va.IsNumber() && vb.IsNumber() {
   357  				env.A = Float64(va.Float64() * vb.Float64())
   358  			} else {
   359  				internal.Panic("mul "+errNeedNumbers, va.simple(), vb.simple())
   360  			}
   361  		case typ.OpDiv:
   362  			if va, vb := env._ref(opa), env._ref(opb); va.IsNumber() && vb.IsNumber() {
   363  				env.A = Float64(va.Float64() / vb.Float64())
   364  			} else {
   365  				internal.Panic("div "+errNeedNumbers, va.simple(), vb.simple())
   366  			}
   367  		case typ.OpIDiv:
   368  			if va, vb := env._ref(opa), env._ref(opb); va.IsNumber() && vb.IsNumber() {
   369  				env.A = Int64(va.Int64() / vb.Int64())
   370  			} else {
   371  				internal.Panic("idiv "+errNeedNumbers, va.simple(), vb.simple())
   372  			}
   373  		case typ.OpMod:
   374  			if va, vb := env._get(opa), env._get(opb); va.IsNumber() && vb.IsNumber() {
   375  				env.A = Int64(va.Int64() % vb.Int64())
   376  			} else {
   377  				internal.Panic("mod "+errNeedNumbers, va.simple(), vb.simple())
   378  			}
   379  		case typ.OpEq:
   380  			env.A = Bool(env._ref(opa).Equal(env._get(opb)))
   381  		case typ.OpNeq:
   382  			env.A = Bool(!env._ref(opa).Equal(env._get(opb)))
   383  		case typ.OpLess:
   384  			if va, vb := env._ref(opa), env._ref(opb); va.IsInt64() && vb.IsInt64() {
   385  				env.A = Bool(va.UnsafeInt64() < vb.UnsafeInt64())
   386  			} else if va.IsNumber() && vb.IsNumber() {
   387  				env.A = Bool(va.Float64() < vb.Float64())
   388  			} else if va.Type() == typ.String && vb.Type() == typ.String {
   389  				env.A = Bool(lessStr(*va, *vb))
   390  			} else {
   391  				internal.Panic("comparison "+errNeedNumbersOrStrings, va.simple(), vb.simple())
   392  			}
   393  		case typ.OpLessEq:
   394  			if va, vb := env._ref(opa), env._ref(opb); va.IsInt64() && vb.IsInt64() {
   395  				env.A = Bool(va.UnsafeInt64() <= vb.UnsafeInt64())
   396  			} else if va.IsNumber() && vb.IsNumber() {
   397  				env.A = Bool(va.Float64() <= vb.Float64())
   398  			} else if va.Type() == typ.String && vb.Type() == typ.String {
   399  				env.A = Bool(!lessStr(*vb, *va))
   400  			} else {
   401  				internal.Panic("comparison "+errNeedNumbersOrStrings, va.simple(), vb.simple())
   402  			}
   403  		case typ.OpNot:
   404  			env.A = Bool(env._get(opa).IsFalse())
   405  		case typ.OpCreateArray:
   406  			env.A = newArray(append([]Value{}, stackEnv.Stack()...)...).ToValue()
   407  			stackEnv.clear()
   408  		case typ.OpCreateObject:
   409  			stk := stackEnv.Stack()
   410  			o := NewObject(len(stk) / 2)
   411  			for i := 0; i < len(stk); i += 2 {
   412  				o.Set(stk[i], stk[i+1])
   413  			}
   414  			env.A = o.ToValue()
   415  			stackEnv.clear()
   416  		case typ.OpIsProto:
   417  			if a, b := env._get(opa), env._get(opb); b.IsString() {
   418  				env.A = Bool(TestShapeFast(a, b.Str()) == nil)
   419  			} else if b.IsObject() {
   420  				env.A = Bool(a.HasPrototype(b.Object()))
   421  			} else {
   422  				env.A = Bool(a.Equal(b))
   423  			}
   424  		case typ.OpStore:
   425  			subject, k, v := env._ref(opa), env._get(opb), env._get(v.C)
   426  			switch subject.Type() {
   427  			case typ.Object:
   428  				subject.Object().Set(k, v)
   429  			case typ.Native:
   430  				if k.IsInt64() {
   431  					subject.Native().Set(k.Int(), v)
   432  				} else {
   433  					subject.Native().SetKey(k, v)
   434  				}
   435  			default:
   436  				internal.Panic("can't index %v using %v", subject.simple(), k.simple())
   437  			}
   438  			env.A = v
   439  		case typ.OpLoad:
   440  			switch a, idx := env._ref(opa), env._get(opb); a.Type() {
   441  			case typ.Object:
   442  				env.A = a.Object().Get(idx)
   443  			case typ.Native:
   444  				if idx.IsInt64() {
   445  					env.A = a.Native().Get(idx.Int())
   446  				} else {
   447  					env.A, _ = a.Native().GetKey(idx)
   448  				}
   449  			case typ.String:
   450  				if idx.IsInt64() {
   451  					env.A = Int64(int64(a.Str()[idx.UnsafeInt64()]))
   452  				} else {
   453  					env.A = setObjectRecv(Proto.Str.Get(idx), *a)
   454  				}
   455  			default:
   456  				env.A = Nil
   457  			}
   458  			env._set(v.C, env.A)
   459  		case typ.OpSlice:
   460  			a, start, end := env._get(opa), env._get(opb), env._get(v.C)
   461  			switch a.Type() {
   462  			case typ.Native:
   463  				if a := a.Native(); a.HasPrototype(&Proto.NativeMap) {
   464  					if v, ok := a.GetKey(start); ok {
   465  						env.A = v
   466  					} else {
   467  						env.A = end
   468  					}
   469  				} else {
   470  					if !start.IsInt64() || !end.IsInt64() {
   471  						internal.Panic("can't slice %v using %v and %v", a.ToValue().simple(), start.simple(), end.simple())
   472  					}
   473  					if end := end.Int(); end == -1 {
   474  						env.A = a.Slice(start.Int(), a.Len()).ToValue()
   475  					} else {
   476  						env.A = a.Slice(start.Int(), end).ToValue()
   477  					}
   478  				}
   479  			case typ.String:
   480  				if !start.IsInt64() || !end.IsInt64() {
   481  					internal.Panic("can't slice %v using %v and %v", a.simple(), start.simple(), end.simple())
   482  				}
   483  				if end := end.Int(); end == -1 {
   484  					env.A = Str(a.Str()[start.Int():a.Len()])
   485  				} else {
   486  					env.A = Str(a.Str()[start.Int():end])
   487  				}
   488  			case typ.Object:
   489  				env.A = a.Object().GetDefault(start, end)
   490  			default:
   491  				internal.Panic("can't slice %v", a.simple())
   492  			}
   493  		case typ.OpPush:
   494  			stackEnv.push(env._get(opa))
   495  		case typ.OpPushUnpack:
   496  			switch a := env._get(opa); a.Type() {
   497  			case typ.Native:
   498  				*stackEnv.stack = append(*stackEnv.stack, a.Native().Values()...)
   499  			case typ.Nil:
   500  			default:
   501  				internal.Panic("arguments unpacking expects array, got %v", a.simple())
   502  			}
   503  		case typ.OpRet:
   504  			v := env._get(opa)
   505  			if len(retStack) == retStackStartSize {
   506  				return v
   507  			}
   508  			// Return to upper stack
   509  			r := retStack[len(retStack)-1]
   510  			cursor = r.Cursor
   511  			K = r.Callable
   512  			code = K.fun.codeSeg.CodePtr()
   513  			env.stackOffset = r.StackOffset
   514  			env.A = v
   515  			env.top = K.fun.top
   516  			*env.stack = (*env.stack)[:env.stackOffset+uint32(r.Callable.fun.stackSize)]
   517  			stackEnv.stackOffset = uint32(len(*env.stack))
   518  			retStack = retStack[:len(retStack)-1]
   519  		case typ.OpFunction:
   520  			if opa == typ.RegA {
   521  				env.A = K.ToValue()
   522  			} else {
   523  				o := env._get(opa).Object().Copy()
   524  				if opb == 1 {
   525  					o.Merge(K)
   526  					for addr, name := range o.fun.caps {
   527  						if name == "" {
   528  							continue
   529  						}
   530  						if uint16(addr) == v.C {
   531  							// Recursive closure, e.g.:
   532  							// function foo()
   533  							//   function bar()
   534  							//     self.bar()
   535  							//   end
   536  							//   return bar
   537  							// end
   538  							o.Set(Str(name), o.ToValue())
   539  						} else {
   540  							o.Set(Str(name), env._get(uint16(addr)))
   541  						}
   542  					}
   543  				}
   544  				env._set(v.C, o.ToValue())
   545  			}
   546  		case typ.OpCall, typ.OpTailCall:
   547  			a := env._refgp(opa)
   548  			if a.Type() != typ.Object {
   549  				internal.Panic("can't call %v", a.simple())
   550  			}
   551  			obj := a.Object()
   552  			cls := obj.fun
   553  			if v.OpcodeExt == 1 {
   554  				stackEnv.push(env._get(opb))
   555  			} else if v.OpcodeExt == 2 {
   556  				stackEnv.push(env._get(opb))
   557  				stackEnv.push(env._get(v.C))
   558  			}
   559  			stackEnv.A = obj.this
   560  			if cls.varg {
   561  				s, w := stackEnv.Stack(), int(cls.numArgs)-1
   562  				if len(s) > w {
   563  					s[w] = newVarargArray(s[w:]).ToValue()
   564  				} else {
   565  					if len(s) < w {
   566  						panicNotEnoughArgs(obj)
   567  					}
   568  					stackEnv.resize(w + 1)
   569  					stackEnv._set(uint16(w), Nil)
   570  				}
   571  			}
   572  			env.checkStackOverflow()
   573  
   574  			last := Stacktrace{
   575  				Callable:    K,
   576  				Cursor:      cursor,
   577  				StackOffset: env.stackOffset,
   578  			}
   579  
   580  			if cls.native != nil {
   581  				stackEnv.top = env.top
   582  				stackEnv.runtime.stack0 = Stacktrace{Callable: obj}
   583  				stackEnv.runtime.stack1 = last
   584  				stackEnv.runtime.stackN = retStack
   585  				cls.native(&stackEnv)
   586  				cursor = stackEnv.runtime.stack1.Cursor
   587  				env.A = stackEnv.A
   588  				stackEnv.runtime = stacktraces{}
   589  				stackEnv.clear()
   590  			} else if v.Opcode == typ.OpCall {
   591  				if stackEnv.Size() < int(cls.numArgs) {
   592  					panicNotEnoughArgs(obj)
   593  				}
   594  				// Switch 'env' to 'stackEnv' and move up 'stackEnv'.
   595  				stackEnv.resizeZero(int(cls.stackSize), int(cls.numArgs))
   596  				cursor = 0
   597  				K = obj
   598  				code = obj.fun.codeSeg.CodePtr()
   599  				env.stackOffset = stackEnv.stackOffset
   600  				env.top = cls.top
   601  				env.A = stackEnv.A
   602  
   603  				retStack = append(retStack, last)
   604  				stackEnv.stackOffset = uint32(len(*env.stack))
   605  			} else {
   606  				if stackEnv.Size() < int(cls.numArgs) {
   607  					panicNotEnoughArgs(obj)
   608  				}
   609  				// Move arguments from 'stackEnv' to 'env'.
   610  				*env.stack = append((*env.stack)[:env.stackOffset], stackEnv.Stack()...)
   611  
   612  				// Resize 'env' to allocate enough space for the next function and move up 'stackEnv'.
   613  				env.resizeZero(int(cls.stackSize), int(cls.numArgs))
   614  				cursor = 0
   615  				K = obj
   616  				code = obj.fun.codeSeg.CodePtr()
   617  				env.top = cls.top
   618  				env.A = stackEnv.A
   619  				stackEnv.stackOffset = uint32(len(*env.stack))
   620  			}
   621  		case typ.OpJmp:
   622  			cursor = uint32(int32(cursor) + v.D())
   623  		case typ.OpJmpFalse:
   624  			if env.A.IsFalse() {
   625  				cursor = uint32(int32(cursor) + v.D())
   626  			}
   627  		case typ.OpLoadTop:
   628  			if a := topSymbols.stack[opa]; opb != typ.RegPhantom {
   629  				env._set(v.C, a.AssertObject("load top").Get(env._get(opb)))
   630  			} else {
   631  				env._set(v.C, a)
   632  			}
   633  		}
   634  	}
   635  }