github.com/goplus/igop@v0.25.0/builtin.go (about)

     1  /*
     2   * Copyright (c) 2022 The GoPlus Authors (goplus.org). All rights reserved.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package igop
    18  
    19  import (
    20  	"bytes"
    21  	"fmt"
    22  	"go/ast"
    23  	"go/token"
    24  	"go/types"
    25  	"reflect"
    26  	"strings"
    27  	"unsafe"
    28  
    29  	"golang.org/x/tools/go/ast/astutil"
    30  	"golang.org/x/tools/go/ssa"
    31  )
    32  
    33  // callBuiltin interprets a call to builtin fn with arguments args,
    34  // returning its result.
    35  func (inter *Interp) callBuiltin(caller *frame, fn *ssa.Builtin, args []value, ssaArgs []ssa.Value) value {
    36  	switch fnName := fn.Name(); fnName {
    37  	case "append":
    38  		if len(args) == 1 {
    39  			return args[0]
    40  		}
    41  		v0 := reflect.ValueOf(args[0])
    42  		v1 := reflect.ValueOf(args[1])
    43  		// append([]byte, ...string) []byte
    44  		if v1.Kind() == reflect.String {
    45  			v1 = reflect.ValueOf([]byte(v1.String()))
    46  		}
    47  		i0 := v0.Len()
    48  		i1 := v1.Len()
    49  		if i0+i1 < i0 {
    50  			panic(runtimeError(errAppendOutOfRange))
    51  		}
    52  		return reflect.AppendSlice(v0, v1).Interface()
    53  
    54  	case "copy": // copy([]T, []T) int or copy([]byte, string) int
    55  		return reflect.Copy(reflect.ValueOf(args[0]), reflect.ValueOf(args[1]))
    56  
    57  	case "close": // close(chan T)
    58  		reflect.ValueOf(args[0]).Close()
    59  		return nil
    60  
    61  	case "delete": // delete(map[K]value, K)
    62  		reflect.ValueOf(args[0]).SetMapIndex(reflect.ValueOf(args[1]), reflect.Value{})
    63  		return nil
    64  
    65  	case "print", "println": // print(any, ...)
    66  		ln := fn.Name() == "println"
    67  		var buf bytes.Buffer
    68  		for i, arg := range args {
    69  			if i > 0 && ln {
    70  				buf.WriteRune(' ')
    71  			}
    72  			if len(ssaArgs) > i {
    73  				typ := inter.toType(ssaArgs[i].Type())
    74  				if typ.Kind() == reflect.Interface {
    75  					writeinterface(&buf, arg)
    76  					continue
    77  				}
    78  			}
    79  			writevalue(&buf, arg, inter.ctx.Mode&EnablePrintAny != 0)
    80  		}
    81  		if ln {
    82  			buf.WriteRune('\n')
    83  		}
    84  		inter.ctx.writeOutput(buf.Bytes())
    85  		return nil
    86  
    87  	case "len":
    88  		return reflect.ValueOf(args[0]).Len()
    89  
    90  	case "cap":
    91  		return reflect.ValueOf(args[0]).Cap()
    92  
    93  	case "real":
    94  		c := reflect.ValueOf(args[0])
    95  		switch c.Kind() {
    96  		case reflect.Complex64:
    97  			return real(complex64(c.Complex()))
    98  		case reflect.Complex128:
    99  			return real(c.Complex())
   100  		default:
   101  			panic(fmt.Sprintf("real: illegal operand: %T", c))
   102  		}
   103  
   104  	case "imag":
   105  		c := reflect.ValueOf(args[0])
   106  		switch c.Kind() {
   107  		case reflect.Complex64:
   108  			return imag(complex64(c.Complex()))
   109  		case reflect.Complex128:
   110  			return imag(c.Complex())
   111  		default:
   112  			panic(fmt.Sprintf("imag: illegal operand: %T", c))
   113  		}
   114  
   115  	case "complex":
   116  		r := reflect.ValueOf(args[0])
   117  		i := reflect.ValueOf(args[1])
   118  		switch r.Kind() {
   119  		case reflect.Float32:
   120  			return complex(float32(r.Float()), float32(i.Float()))
   121  		case reflect.Float64:
   122  			return complex(r.Float(), i.Float())
   123  		default:
   124  			panic(fmt.Sprintf("complex: illegal operand: %v", r.Kind()))
   125  		}
   126  
   127  	case "panic":
   128  		// ssa.Panic handles most cases; this is only for "go
   129  		// panic" or "defer panic".
   130  		panic(PanicError{stack: debugStack(caller), Value: args[0]})
   131  
   132  	case "recover":
   133  		return doRecover(caller)
   134  
   135  	case "ssa:wrapnilchk":
   136  		recv := args[0]
   137  		if reflect.ValueOf(recv).IsNil() {
   138  			recvType := args[1]
   139  			methodName := args[2]
   140  			var info value
   141  			if s, ok := recvType.(string); ok && strings.HasPrefix(s, "main.") {
   142  				info = s[5:]
   143  			} else {
   144  				info = recvType
   145  			}
   146  			panic(plainError(fmt.Sprintf("value method %s.%s called using nil *%s pointer",
   147  				recvType, methodName, info)))
   148  		}
   149  		return recv
   150  
   151  	case "Add":
   152  		ptr := args[0].(unsafe.Pointer)
   153  		length := asInt(args[1])
   154  		return unsafe.Pointer(uintptr(ptr) + uintptr(length))
   155  	case "Slice":
   156  		//func Slice(ptr *ArbitraryType, len IntegerType) []ArbitraryType
   157  		//(*[len]ArbitraryType)(unsafe.Pointer(ptr))[:]
   158  		ptr := reflect.ValueOf(args[0])
   159  		length := asInt(args[1])
   160  		etyp := ptr.Type().Elem()
   161  		if ptr.IsNil() {
   162  			if length == 0 {
   163  				return reflect.New(reflect.SliceOf(etyp)).Elem().Interface()
   164  			}
   165  			panic(runtimeError("unsafe.Slice: ptr is nil and len is not zero"))
   166  		}
   167  		mem, overflow := mulUintptr(etyp.Size(), uintptr(length))
   168  		if overflow || mem > -uintptr(ptr.Pointer()) {
   169  			panic(runtimeError("unsafe.Slice: len out of range"))
   170  		}
   171  		typ := reflect.ArrayOf(length, etyp)
   172  		v := reflect.NewAt(typ, unsafe.Pointer(ptr.Pointer()))
   173  		return v.Elem().Slice(0, length).Interface()
   174  	case "SliceData":
   175  		// SliceData returns a pointer to the underlying array of the argument
   176  		// slice.
   177  		//   - If cap(slice) > 0, SliceData returns &slice[:1][0].
   178  		//   - If slice == nil, SliceData returns nil.
   179  		//   - Otherwise, SliceData returns a non-nil pointer to an
   180  		//     unspecified memory address.
   181  		// func SliceData(slice []ArbitraryType) *ArbitraryType
   182  		v := reflect.ValueOf(args[0])
   183  		if v.Cap() > 0 {
   184  			return v.Slice(0, 1).Index(0).Addr().Interface()
   185  		} else if v.IsNil() {
   186  			return reflect.Zero(reflect.PtrTo(v.Type().Elem())).Interface()
   187  		} else {
   188  			return reflect.New(v.Type().Elem()).Interface()
   189  		}
   190  	case "String":
   191  		// String returns a string value whose underlying bytes
   192  		// start at ptr and whose length is len.
   193  		//
   194  		// The len argument must be of integer type or an untyped constant.
   195  		// A constant len argument must be non-negative and representable by a value of type int;
   196  		// if it is an untyped constant it is given type int.
   197  		// At run time, if len is negative, or if ptr is nil and len is not zero,
   198  		// a run-time panic occurs.
   199  		//
   200  		// Since Go strings are immutable, the bytes passed to String
   201  		// must not be modified afterwards.
   202  		// func String(ptr *byte, len IntegerType) string
   203  		ptr := args[0].(*byte)
   204  		length := asInt(args[1])
   205  		if ptr == nil {
   206  			if length == 0 {
   207  				return ""
   208  			}
   209  			panic(runtimeError("unsafe.String: ptr is nil and len is not zero"))
   210  		}
   211  		mem, overflow := mulUintptr(1, uintptr(length))
   212  		if overflow || mem > -uintptr(unsafe.Pointer(ptr)) {
   213  			panic(runtimeError("unsafe.String: len out of range"))
   214  		}
   215  		sh := reflect.StringHeader{Data: uintptr(unsafe.Pointer(ptr)), Len: length}
   216  		return *(*string)(unsafe.Pointer(&sh))
   217  	case "StringData":
   218  		// StringData returns a pointer to the underlying bytes of str.
   219  		// For an empty string the return value is unspecified, and may be nil.
   220  		//
   221  		// Since Go strings are immutable, the bytes returned by StringData
   222  		// must not be modified.
   223  		// func StringData(str string) *byte
   224  		s := args[0].(string)
   225  		data := (*reflect.StringHeader)(unsafe.Pointer(&s)).Data
   226  		return (*byte)(unsafe.Pointer(data))
   227  	default:
   228  		panic("unknown built-in: " + fnName)
   229  	}
   230  }
   231  
   232  // callBuiltinDiscardsResult interprets a call to builtin fn with arguments args,
   233  // discards its result.
   234  func (inter *Interp) callBuiltinDiscardsResult(caller *frame, fn *ssa.Builtin, args []value, ssaArgs []ssa.Value) {
   235  	switch fnName := fn.Name(); fnName {
   236  	case "append":
   237  		panic("discards result of " + fnName)
   238  
   239  	case "copy": // copy([]T, []T) int or copy([]byte, string) int
   240  		reflect.Copy(reflect.ValueOf(args[0]), reflect.ValueOf(args[1]))
   241  
   242  	case "close": // close(chan T)
   243  		reflect.ValueOf(args[0]).Close()
   244  
   245  	case "delete": // delete(map[K]value, K)
   246  		reflect.ValueOf(args[0]).SetMapIndex(reflect.ValueOf(args[1]), reflect.Value{})
   247  
   248  	case "print", "println": // print(any, ...)
   249  		ln := fn.Name() == "println"
   250  		var buf bytes.Buffer
   251  		for i, arg := range args {
   252  			if i > 0 && ln {
   253  				buf.WriteRune(' ')
   254  			}
   255  			if len(ssaArgs) > i {
   256  				typ := inter.toType(ssaArgs[i].Type())
   257  				if typ.Kind() == reflect.Interface {
   258  					writeinterface(&buf, arg)
   259  					continue
   260  				}
   261  			}
   262  			writevalue(&buf, arg, inter.ctx.Mode&EnablePrintAny != 0)
   263  		}
   264  		if ln {
   265  			buf.WriteRune('\n')
   266  		}
   267  		inter.ctx.writeOutput(buf.Bytes())
   268  
   269  	case "len":
   270  		panic("discards result of " + fnName)
   271  
   272  	case "cap":
   273  		panic("discards result of " + fnName)
   274  
   275  	case "real":
   276  		panic("discards result of " + fnName)
   277  
   278  	case "imag":
   279  		panic("discards result of " + fnName)
   280  
   281  	case "complex":
   282  		panic("discards result of " + fnName)
   283  
   284  	case "panic":
   285  		// ssa.Panic handles most cases; this is only for "go
   286  		// panic" or "defer panic".
   287  		panic(PanicError{stack: debugStack(caller), Value: args[0]})
   288  
   289  	case "recover":
   290  		doRecover(caller)
   291  
   292  	case "ssa:wrapnilchk":
   293  		recv := args[0]
   294  		if reflect.ValueOf(recv).IsNil() {
   295  			recvType := args[1]
   296  			methodName := args[2]
   297  			var info value
   298  			if s, ok := recvType.(string); ok && strings.HasPrefix(s, "main.") {
   299  				info = s[5:]
   300  			} else {
   301  				info = recvType
   302  			}
   303  			panic(plainError(fmt.Sprintf("value method %s.%s called using nil *%s pointer",
   304  				recvType, methodName, info)))
   305  		}
   306  
   307  	case "Add":
   308  		panic("discards result of " + fnName)
   309  
   310  	case "Slice":
   311  		//func Slice(ptr *ArbitraryType, len IntegerType) []ArbitraryType
   312  		//(*[len]ArbitraryType)(unsafe.Pointer(ptr))[:]
   313  		panic("discards result of " + fnName)
   314  
   315  	case "SliceData":
   316  		panic("discards result of " + fnName)
   317  
   318  	case "String":
   319  		panic("discards result of " + fnName)
   320  
   321  	case "StringData":
   322  		panic("discards result of " + fnName)
   323  
   324  	default:
   325  		panic("unknown built-in: " + fnName)
   326  	}
   327  }
   328  
   329  // callBuiltin interprets a call to builtin fn with arguments args,
   330  // returning its result.
   331  func (interp *Interp) callBuiltinByStack(caller *frame, fn string, ssaArgs []ssa.Value, ir register, ia []register) {
   332  	switch fn {
   333  	case "append":
   334  		if len(ia) == 1 {
   335  			caller.copyReg(ir, ia[0])
   336  			return
   337  		}
   338  		arg0 := caller.reg(ia[0])
   339  		arg1 := caller.reg(ia[1])
   340  		v0 := reflect.ValueOf(arg0)
   341  		v1 := reflect.ValueOf(arg1)
   342  		// append([]byte, ...string) []byte
   343  		if v1.Kind() == reflect.String {
   344  			v1 = reflect.ValueOf([]byte(v1.String()))
   345  		}
   346  		i0 := v0.Len()
   347  		i1 := v1.Len()
   348  		if i0+i1 < i0 {
   349  			panic(runtimeError(errAppendOutOfRange))
   350  		}
   351  		caller.setReg(ir, reflect.AppendSlice(v0, v1).Interface())
   352  
   353  	case "copy": // copy([]T, []T) int or copy([]byte, string) int
   354  		arg0 := caller.reg(ia[0])
   355  		arg1 := caller.reg(ia[1])
   356  		caller.setReg(ir, reflect.Copy(reflect.ValueOf(arg0), reflect.ValueOf(arg1)))
   357  
   358  	case "close": // close(chan T)
   359  		arg0 := caller.reg(ia[0])
   360  		reflect.ValueOf(arg0).Close()
   361  
   362  	case "delete": // delete(map[K]value, K)
   363  		arg0 := caller.reg(ia[0])
   364  		arg1 := caller.reg(ia[1])
   365  		reflect.ValueOf(arg0).SetMapIndex(reflect.ValueOf(arg1), reflect.Value{})
   366  
   367  	case "print", "println": // print(any, ...)
   368  		ln := fn == "println"
   369  		var buf bytes.Buffer
   370  		for i := 0; i < len(ia); i++ {
   371  			arg := caller.reg(ia[i])
   372  			if i > 0 && ln {
   373  				buf.WriteRune(' ')
   374  			}
   375  			if len(ssaArgs) > i {
   376  				typ := interp.toType(ssaArgs[i].Type())
   377  				if typ.Kind() == reflect.Interface {
   378  					writeinterface(&buf, arg)
   379  					continue
   380  				}
   381  			}
   382  			writevalue(&buf, arg, interp.ctx.Mode&EnablePrintAny != 0)
   383  		}
   384  		if ln {
   385  			buf.WriteRune('\n')
   386  		}
   387  		interp.ctx.writeOutput(buf.Bytes())
   388  
   389  	case "len":
   390  		arg0 := caller.reg(ia[0])
   391  		caller.setReg(ir, reflect.ValueOf(arg0).Len())
   392  
   393  	case "cap":
   394  		arg0 := caller.reg(ia[0])
   395  		caller.setReg(ir, reflect.ValueOf(arg0).Cap())
   396  
   397  	case "real":
   398  		arg0 := caller.reg(ia[0])
   399  		c := reflect.ValueOf(arg0)
   400  		switch c.Kind() {
   401  		case reflect.Complex64:
   402  			caller.setReg(ir, real(complex64(c.Complex())))
   403  		case reflect.Complex128:
   404  			caller.setReg(ir, real(c.Complex()))
   405  		default:
   406  			panic(fmt.Sprintf("real: illegal operand: %T", c))
   407  		}
   408  
   409  	case "imag":
   410  		arg0 := caller.reg(ia[0])
   411  		c := reflect.ValueOf(arg0)
   412  		switch c.Kind() {
   413  		case reflect.Complex64:
   414  			caller.setReg(ir, imag(complex64(c.Complex())))
   415  		case reflect.Complex128:
   416  			caller.setReg(ir, imag(c.Complex()))
   417  		default:
   418  			panic(fmt.Sprintf("imag: illegal operand: %T", c))
   419  		}
   420  
   421  	case "complex":
   422  		arg0 := caller.reg(ia[0])
   423  		arg1 := caller.reg(ia[1])
   424  		r := reflect.ValueOf(arg0)
   425  		i := reflect.ValueOf(arg1)
   426  		switch r.Kind() {
   427  		case reflect.Float32:
   428  			caller.setReg(ir, complex(float32(r.Float()), float32(i.Float())))
   429  		case reflect.Float64:
   430  			caller.setReg(ir, complex(r.Float(), i.Float()))
   431  		default:
   432  			panic(fmt.Sprintf("complex: illegal operand: %v", r.Kind()))
   433  		}
   434  
   435  	case "panic":
   436  		// ssa.Panic handles most cases; this is only for "go
   437  		// panic" or "defer panic".
   438  		arg0 := caller.reg(ia[0])
   439  		panic(PanicError{stack: debugStack(caller), Value: arg0})
   440  
   441  	case "recover":
   442  		caller.setReg(ir, doRecover(caller))
   443  
   444  	case "ssa:wrapnilchk":
   445  		recv := caller.reg(ia[0])
   446  		if reflect.ValueOf(recv).IsNil() {
   447  			recvType := caller.reg(ia[1])
   448  			methodName := caller.reg(ia[2])
   449  			var info value
   450  			if s, ok := recvType.(string); ok && strings.HasPrefix(s, "main.") {
   451  				info = s[5:]
   452  			} else {
   453  				info = recvType
   454  			}
   455  			panic(plainError(fmt.Sprintf("value method %s.%s called using nil *%s pointer",
   456  				recvType, methodName, info)))
   457  		}
   458  		caller.setReg(ir, recv)
   459  
   460  	case "Add":
   461  		arg0 := caller.reg(ia[0])
   462  		arg1 := caller.reg(ia[1])
   463  		ptr := arg0.(unsafe.Pointer)
   464  		length := asInt(arg1)
   465  		caller.setReg(ir, unsafe.Pointer(uintptr(ptr)+uintptr(length)))
   466  	case "Slice":
   467  		//func Slice(ptr *ArbitraryType, len IntegerType) []ArbitraryType
   468  		//(*[len]ArbitraryType)(unsafe.Pointer(ptr))[:]
   469  		arg0 := caller.reg(ia[0])
   470  		arg1 := caller.reg(ia[1])
   471  		ptr := reflect.ValueOf(arg0)
   472  		etyp := ptr.Type().Elem()
   473  		length := asInt(arg1)
   474  		if ptr.IsNil() {
   475  			if length == 0 {
   476  				caller.setReg(ir, reflect.New(reflect.SliceOf(etyp)).Elem().Interface())
   477  				return
   478  			}
   479  			panic(runtimeError("unsafe.Slice: ptr is nil and len is not zero"))
   480  		}
   481  		mem, overflow := mulUintptr(etyp.Size(), uintptr(length))
   482  		if overflow || mem > -uintptr(ptr.Pointer()) {
   483  			panic(runtimeError("unsafe.Slice: len out of range"))
   484  		}
   485  		typ := reflect.ArrayOf(length, etyp)
   486  		v := reflect.NewAt(typ, unsafe.Pointer(ptr.Pointer()))
   487  		caller.setReg(ir, v.Elem().Slice(0, length).Interface())
   488  	case "SliceData":
   489  		// SliceData returns a pointer to the underlying array of the argument
   490  		// slice.
   491  		//   - If cap(slice) > 0, SliceData returns &slice[:1][0].
   492  		//   - If slice == nil, SliceData returns nil.
   493  		//   - Otherwise, SliceData returns a non-nil pointer to an
   494  		//     unspecified memory address.
   495  		// func SliceData(slice []ArbitraryType) *ArbitraryType
   496  		arg0 := caller.reg(ia[0])
   497  		v := reflect.ValueOf(arg0)
   498  		if v.Cap() > 0 {
   499  			caller.setReg(ir, v.Slice(0, 1).Index(0).Addr().Interface())
   500  		} else if v.IsNil() {
   501  			caller.setReg(ir, reflect.Zero(reflect.PtrTo(v.Type().Elem())).Interface())
   502  		} else {
   503  			caller.setReg(ir, reflect.New(v.Type().Elem()).Interface())
   504  		}
   505  	case "String":
   506  		// String returns a string value whose underlying bytes
   507  		// start at ptr and whose length is len.
   508  		//
   509  		// The len argument must be of integer type or an untyped constant.
   510  		// A constant len argument must be non-negative and representable by a value of type int;
   511  		// if it is an untyped constant it is given type int.
   512  		// At run time, if len is negative, or if ptr is nil and len is not zero,
   513  		// a run-time panic occurs.
   514  		//
   515  		// Since Go strings are immutable, the bytes passed to String
   516  		// must not be modified afterwards.
   517  		// func String(ptr *byte, len IntegerType) string
   518  		ptr := caller.reg(ia[0]).(*byte)
   519  		length := asInt(caller.reg(ia[1]))
   520  		if ptr == nil {
   521  			if length == 0 {
   522  				caller.setReg(ir, "")
   523  				return
   524  			}
   525  			panic(runtimeError("unsafe.String: ptr is nil and len is not zero"))
   526  		}
   527  		mem, overflow := mulUintptr(1, uintptr(length))
   528  		if overflow || mem > -uintptr(unsafe.Pointer(ptr)) {
   529  			panic(runtimeError("unsafe.String: len out of range"))
   530  		}
   531  		sh := reflect.StringHeader{Data: uintptr(unsafe.Pointer(ptr)), Len: length}
   532  		caller.setReg(ir, *(*string)(unsafe.Pointer(&sh)))
   533  	case "StringData":
   534  		// StringData returns a pointer to the underlying bytes of str.
   535  		// For an empty string the return value is unspecified, and may be nil.
   536  		//
   537  		// Since Go strings are immutable, the bytes returned by StringData
   538  		// must not be modified.
   539  		// func StringData(str string) *byte
   540  		s := caller.string(ia[0])
   541  		data := (*reflect.StringHeader)(unsafe.Pointer(&s)).Data
   542  		caller.setReg(ir, (*byte)(unsafe.Pointer(data)))
   543  	case "Sizeof": // instance of generic function
   544  		typ := reflect.TypeOf(caller.reg(ia[0]))
   545  		caller.setReg(ir, uintptr(typ.Size()))
   546  	case "Alignof": // instance of generic function
   547  		typ := reflect.TypeOf(caller.reg(ia[0]))
   548  		caller.setReg(ir, uintptr(typ.Align()))
   549  	case "Offsetof": // instance of generic function
   550  		offset, err := builtinOffsetof(caller.pfn, caller.ipc-1)
   551  		if err != nil {
   552  			panic(err)
   553  		}
   554  		caller.setReg(ir, uintptr(offset))
   555  	case "clear":
   556  		arg0 := caller.reg(ia[0])
   557  		valueClear(reflect.ValueOf(arg0))
   558  	case "max":
   559  		v := reflect.ValueOf(caller.reg(ia[0]))
   560  		for _, i := range ia {
   561  			arg := reflect.ValueOf(caller.reg(i))
   562  			if i > 0 {
   563  				switch v.Kind() {
   564  				case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   565  					if v.Int() < arg.Int() {
   566  						v = arg
   567  					}
   568  				case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
   569  					if v.Uint() < arg.Uint() {
   570  						v = arg
   571  					}
   572  				case reflect.Float32, reflect.Float64:
   573  					if v.Float() < arg.Float() {
   574  						v = arg
   575  					}
   576  				case reflect.String:
   577  					if v.String() < arg.String() {
   578  						v = arg
   579  					}
   580  				}
   581  			}
   582  		}
   583  		caller.setReg(ir, v.Interface())
   584  	case "min":
   585  		v := reflect.ValueOf(caller.reg(ia[0]))
   586  		for _, i := range ia {
   587  			arg := reflect.ValueOf(caller.reg(i))
   588  			if i > 0 {
   589  				switch v.Kind() {
   590  				case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   591  					if v.Int() > arg.Int() {
   592  						v = arg
   593  					}
   594  				case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
   595  					if v.Uint() > arg.Uint() {
   596  						v = arg
   597  					}
   598  				case reflect.Float32, reflect.Float64:
   599  					if v.Float() > arg.Float() {
   600  						v = arg
   601  					}
   602  				case reflect.String:
   603  					if v.String() > arg.String() {
   604  						v = arg
   605  					}
   606  				}
   607  			}
   608  		}
   609  		caller.setReg(ir, v.Interface())
   610  	default:
   611  		panic("unknown built-in: " + fn)
   612  	}
   613  }
   614  
   615  func valueClear(v reflect.Value) {
   616  	reflect.ValueOf(v).MethodByName("Clear").Call(nil)
   617  }
   618  
   619  const ptrSize = 4 << (^uintptr(0) >> 63)
   620  
   621  const maxUintptr = ^uintptr(0)
   622  
   623  // mulUintptr returns a * b and whether the multiplication overflowed.
   624  // On supported platforms this is an intrinsic lowered by the compiler.
   625  func mulUintptr(a, b uintptr) (uintptr, bool) {
   626  	if a|b < 1<<(4*ptrSize) || a == 0 {
   627  		return a * b, false
   628  	}
   629  	overflow := b > maxUintptr/a
   630  	return a * b, overflow
   631  }
   632  
   633  func builtinOffsetof(pfn *function, pc int) (int64, error) {
   634  	pos := pfn.ssaInstrs[pc].Pos()
   635  	paths, info, ok := pathEnclosingInterval(pfn.Interp.ctx, pos)
   636  	if !ok {
   637  		return -1, plainError("unsafe.Offsetof not found code")
   638  	}
   639  	call, ok := paths[0].(*ast.CallExpr)
   640  	if !ok {
   641  		return -1, plainError("unsafe.Offsetof not found call")
   642  	}
   643  	selx, ok := call.Args[0].(*ast.SelectorExpr)
   644  	if !ok {
   645  		return -1, plainError("unsafe.Offsetof not found selector expr")
   646  	}
   647  	sel, _ := info.Selections[selx]
   648  	if sel == nil {
   649  		return -1, plainError("unsafe.Offsetof not found selector type")
   650  	}
   651  	instrs, found := foundFieldAddr(pfn, pc)
   652  	if !found || len(sel.Index()) > len(instrs) {
   653  		return -1, plainError("unsafe.Offsetof not found FieldAddr instr")
   654  	}
   655  	instr := instrs[len(sel.Index())-1]
   656  	return selOffsetof(pfn.Interp.ctx.sizes, instr.X.Type().Underlying().(*types.Pointer).Elem().Underlying().(*types.Struct), sel.Index(), selx.Sel.Name)
   657  }
   658  
   659  func foundFieldAddr(pfn *function, pc int) (instrs []*ssa.FieldAddr, found bool) {
   660  	for pc > 0 {
   661  		pc--
   662  		if fd, ok := pfn.ssaInstrs[pc].(*ssa.FieldAddr); ok {
   663  			found = true
   664  			instrs = append(instrs, fd)
   665  		} else if found {
   666  			return
   667  		}
   668  	}
   669  	return
   670  }
   671  
   672  func pathEnclosingInterval(ctx *Context, pos token.Pos) (path []ast.Node, info *types.Info, exact bool) {
   673  	for _, sp := range ctx.pkgs {
   674  		for _, file := range sp.Files {
   675  			if pos >= file.Pos() && pos < file.End() {
   676  				path, exact = astutil.PathEnclosingInterval(file, pos, pos)
   677  				if exact {
   678  					info = sp.Info
   679  					return
   680  				}
   681  			}
   682  		}
   683  	}
   684  	return
   685  }
   686  
   687  func selOffsetof(sizes types.Sizes, typ types.Type, index []int, sel string) (int64, error) {
   688  	var o int64
   689  	var indirectType int
   690  	for n, i := range index {
   691  		if n > 0 {
   692  			if t, ok := typ.(*types.Pointer); ok {
   693  				typ = t.Elem()
   694  				indirectType = n
   695  			}
   696  			if t, ok := typ.(*types.Named); ok {
   697  				typ = t.Underlying()
   698  			}
   699  		}
   700  		s := typ.(*types.Struct)
   701  		o += structOffsetsof(sizes, s)[i]
   702  		typ = s.Field(i).Type()
   703  	}
   704  	if indirectType > 0 {
   705  		return -1, fmt.Errorf("invalid argument: field %v is embedded via a pointer", sel)
   706  	}
   707  	return o, nil
   708  }
   709  
   710  func structOffsetsof(sizes types.Sizes, t *types.Struct) []int64 {
   711  	var fields []*types.Var
   712  	for i := 0; i < t.NumFields(); i++ {
   713  		fields = append(fields, t.Field(i))
   714  	}
   715  	return sizes.Offsetsof(fields)
   716  }