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 }