1// Copyright 2013 The Go Authors.  All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package interp
6
7// Emulated functions that we cannot interpret because they are
8// external or because they use "unsafe" or "reflect" operations.
9
10import (
11	"go/types"
12	"math"
13	"os"
14	"runtime"
15	"strings"
16	"sync/atomic"
17	"time"
18	"unsafe"
19
20	"golang.org/x/tools/go/ssa"
21)
22
23type externalFn func(fr *frame, args []value) value
24
25// TODO(adonovan): fix: reflect.Value abstracts an lvalue or an
26// rvalue; Set() causes mutations that can be observed via aliases.
27// We have not captured that correctly here.
28
29// Key strings are from Function.String().
30var externals = make(map[string]externalFn)
31
32func init() {
33	// That little dot ۰ is an Arabic zero numeral (U+06F0), categories [Nd].
34	for k, v := range map[string]externalFn{
35		"(*sync.Pool).Get":                    ext۰sync۰Pool۰Get,
36		"(*sync.Pool).Put":                    ext۰nop,
37		"(reflect.Value).Bool":                ext۰reflect۰Value۰Bool,
38		"(reflect.Value).CanAddr":             ext۰reflect۰Value۰CanAddr,
39		"(reflect.Value).CanInterface":        ext۰reflect۰Value۰CanInterface,
40		"(reflect.Value).Elem":                ext۰reflect۰Value۰Elem,
41		"(reflect.Value).Field":               ext۰reflect۰Value۰Field,
42		"(reflect.Value).Float":               ext۰reflect۰Value۰Float,
43		"(reflect.Value).Index":               ext۰reflect۰Value۰Index,
44		"(reflect.Value).Int":                 ext۰reflect۰Value۰Int,
45		"(reflect.Value).Interface":           ext۰reflect۰Value۰Interface,
46		"(reflect.Value).IsNil":               ext۰reflect۰Value۰IsNil,
47		"(reflect.Value).IsValid":             ext۰reflect۰Value۰IsValid,
48		"(reflect.Value).Kind":                ext۰reflect۰Value۰Kind,
49		"(reflect.Value).Len":                 ext۰reflect۰Value۰Len,
50		"(reflect.Value).MapIndex":            ext۰reflect۰Value۰MapIndex,
51		"(reflect.Value).MapKeys":             ext۰reflect۰Value۰MapKeys,
52		"(reflect.Value).NumField":            ext۰reflect۰Value۰NumField,
53		"(reflect.Value).NumMethod":           ext۰reflect۰Value۰NumMethod,
54		"(reflect.Value).Pointer":             ext۰reflect۰Value۰Pointer,
55		"(reflect.Value).Set":                 ext۰reflect۰Value۰Set,
56		"(reflect.Value).String":              ext۰reflect۰Value۰String,
57		"(reflect.Value).Type":                ext۰reflect۰Value۰Type,
58		"(reflect.Value).Uint":                ext۰reflect۰Value۰Uint,
59		"(reflect.error).Error":               ext۰reflect۰error۰Error,
60		"(reflect.rtype).Bits":                ext۰reflect۰rtype۰Bits,
61		"(reflect.rtype).Elem":                ext۰reflect۰rtype۰Elem,
62		"(reflect.rtype).Field":               ext۰reflect۰rtype۰Field,
63		"(reflect.rtype).In":                  ext۰reflect۰rtype۰In,
64		"(reflect.rtype).Kind":                ext۰reflect۰rtype۰Kind,
65		"(reflect.rtype).NumField":            ext۰reflect۰rtype۰NumField,
66		"(reflect.rtype).NumIn":               ext۰reflect۰rtype۰NumIn,
67		"(reflect.rtype).NumMethod":           ext۰reflect۰rtype۰NumMethod,
68		"(reflect.rtype).NumOut":              ext۰reflect۰rtype۰NumOut,
69		"(reflect.rtype).Out":                 ext۰reflect۰rtype۰Out,
70		"(reflect.rtype).Size":                ext۰reflect۰rtype۰Size,
71		"(reflect.rtype).String":              ext۰reflect۰rtype۰String,
72		"bytes.init":                          ext۰nop, // avoid asm dependency
73		"bytes.Equal":                         ext۰bytes۰Equal,
74		"bytes.IndexByte":                     ext۰bytes۰IndexByte,
75		"hash/crc32.haveSSE42":                ext۰crc32۰haveSSE42,
76		"internal/cpu.cpuid":                  ext۰cpu۰cpuid,
77		"internal/syscall/unix.syscall_fcntl": ext۰syscall۰unix۰syscall_fcntl,
78		"math.Abs":                            ext۰math۰Abs,
79		"math.Exp":                            ext۰math۰Exp,
80		"math.Float32bits":                    ext۰math۰Float32bits,
81		"math.Float32frombits":                ext۰math۰Float32frombits,
82		"math.Float64bits":                    ext۰math۰Float64bits,
83		"math.Float64frombits":                ext۰math۰Float64frombits,
84		"math.Ldexp":                          ext۰math۰Ldexp,
85		"math.Log":                            ext۰math۰Log,
86		"math.Min":                            ext۰math۰Min,
87		"math.hasSSE4":                        ext۰math۰hasSSE4,
88		"math.hasVectorFacility":              ext۰math۰hasVectorFacility,
89		"os.runtime_args":                     ext۰os۰runtime_args,
90		"os.runtime_beforeExit":               ext۰nop,
91		"os/signal.init":                      ext۰nop,
92		"reflect.New":                         ext۰reflect۰New,
93		"reflect.SliceOf":                     ext۰reflect۰SliceOf,
94		"reflect.TypeOf":                      ext۰reflect۰TypeOf,
95		"reflect.ValueOf":                     ext۰reflect۰ValueOf,
96		"reflect.Zero":                        ext۰reflect۰Zero,
97		"reflect.init":                        ext۰reflect۰Init,
98		"reflect.valueInterface":              ext۰reflect۰valueInterface,
99		"runtime.Breakpoint":                  ext۰runtime۰Breakpoint,
100		"runtime.Caller":                      ext۰runtime۰Caller,
101		"runtime.Callers":                     ext۰runtime۰Callers,
102		"runtime.FuncForPC":                   ext۰runtime۰FuncForPC,
103		"runtime.GC":                          ext۰runtime۰GC,
104		"runtime.GOMAXPROCS":                  ext۰runtime۰GOMAXPROCS,
105		"runtime.Goexit":                      ext۰runtime۰Goexit,
106		"runtime.Gosched":                     ext۰runtime۰Gosched,
107		"runtime.init":                        ext۰nop,
108		"runtime.KeepAlive":                   ext۰nop,
109		"runtime.NumCPU":                      ext۰runtime۰NumCPU,
110		"runtime.NumGoroutine":                ext۰runtime۰NumGoroutine,
111		"runtime.ReadMemStats":                ext۰runtime۰ReadMemStats,
112		"runtime.SetFinalizer":                ext۰nop, // ignore
113		"(*runtime.Func).Entry":               ext۰runtime۰Func۰Entry,
114		"(*runtime.Func).FileLine":            ext۰runtime۰Func۰FileLine,
115		"(*runtime.Func).Name":                ext۰runtime۰Func۰Name,
116		"runtime.environ":                     ext۰runtime۰environ,
117		"runtime.getgoroot":                   ext۰runtime۰getgoroot,
118		"strings.init":                        ext۰nop, // avoid asm dependency
119		"strings.Count":                       ext۰strings۰Count,
120		"strings.Index":                       ext۰strings۰Index,
121		"strings.IndexByte":                   ext۰strings۰IndexByte,
122		"sync.runtime_Semacquire":             ext۰nop, // unimplementable
123		"sync.runtime_Semrelease":             ext۰nop, // unimplementable
124		"sync.runtime_Syncsemcheck":           ext۰nop, // unimplementable
125		"sync.runtime_notifyListCheck":        ext۰nop,
126		"sync.runtime_registerPoolCleanup":    ext۰nop,
127		"sync/atomic.AddInt32":                ext۰atomic۰AddInt32,
128		"sync/atomic.AddUint32":               ext۰atomic۰AddUint32,
129		"sync/atomic.CompareAndSwapInt32":     ext۰atomic۰CompareAndSwapInt32,
130		"sync/atomic.CompareAndSwapUint32":    ext۰atomic۰CompareAndSwapUint32,
131		"sync/atomic.LoadInt32":               ext۰atomic۰LoadInt32,
132		"sync/atomic.LoadUint32":              ext۰atomic۰LoadUint32,
133		"sync/atomic.StoreInt32":              ext۰atomic۰StoreInt32,
134		"sync/atomic.StoreUint32":             ext۰atomic۰StoreUint32,
135		"sync/atomic.AddInt64":                ext۰atomic۰AddInt64,
136		"sync/atomic.AddUint64":               ext۰atomic۰AddUint64,
137		"sync/atomic.CompareAndSwapInt64":     ext۰atomic۰CompareAndSwapInt64,
138		"sync/atomic.CompareAndSwapUint64":    ext۰atomic۰CompareAndSwapUint64,
139		"sync/atomic.LoadInt64":               ext۰atomic۰LoadInt64,
140		"sync/atomic.LoadUint64":              ext۰atomic۰LoadUint64,
141		"sync/atomic.StoreInt64":              ext۰atomic۰StoreInt64,
142		"sync/atomic.StoreUint64":             ext۰atomic۰StoreUint64,
143		"(*sync/atomic.Value).Load":           ext۰atomic۰ValueLoad,
144		"(*sync/atomic.Value).Store":          ext۰atomic۰ValueStore,
145		"testing.MainStart":                   ext۰testing۰MainStart,
146		"time.Sleep":                          ext۰time۰Sleep,
147		"time.now":                            ext۰time۰now,
148	} {
149		externals[k] = v
150	}
151}
152
153// wrapError returns an interpreted 'error' interface value for err.
154func wrapError(err error) value {
155	if err == nil {
156		return iface{}
157	}
158	return iface{t: errorType, v: err.Error()}
159}
160
161func ext۰nop(fr *frame, args []value) value { return nil }
162
163func ext۰sync۰Pool۰Get(fr *frame, args []value) value {
164	Pool := fr.i.prog.ImportedPackage("sync").Type("Pool").Object()
165	_, newIndex, _ := types.LookupFieldOrMethod(Pool.Type(), false, Pool.Pkg(), "New")
166
167	if New := (*args[0].(*value)).(structure)[newIndex[0]]; New != nil {
168		return call(fr.i, fr, 0, New, nil)
169	}
170	return nil
171}
172
173func ext۰bytes۰Equal(fr *frame, args []value) value {
174	// func Equal(a, b []byte) bool
175	a := args[0].([]value)
176	b := args[1].([]value)
177	if len(a) != len(b) {
178		return false
179	}
180	for i := range a {
181		if a[i] != b[i] {
182			return false
183		}
184	}
185	return true
186}
187
188func ext۰bytes۰IndexByte(fr *frame, args []value) value {
189	// func IndexByte(s []byte, c byte) int
190	s := args[0].([]value)
191	c := args[1].(byte)
192	for i, b := range s {
193		if b.(byte) == c {
194			return i
195		}
196	}
197	return -1
198}
199
200func ext۰crc32۰haveSSE42(fr *frame, args []value) value {
201	return false
202}
203
204func ext۰math۰Float64frombits(fr *frame, args []value) value {
205	return math.Float64frombits(args[0].(uint64))
206}
207
208func ext۰math۰Float64bits(fr *frame, args []value) value {
209	return math.Float64bits(args[0].(float64))
210}
211
212func ext۰math۰Float32frombits(fr *frame, args []value) value {
213	return math.Float32frombits(args[0].(uint32))
214}
215
216func ext۰math۰Abs(fr *frame, args []value) value {
217	return math.Abs(args[0].(float64))
218}
219
220func ext۰math۰Exp(fr *frame, args []value) value {
221	return math.Exp(args[0].(float64))
222}
223
224func ext۰math۰Float32bits(fr *frame, args []value) value {
225	return math.Float32bits(args[0].(float32))
226}
227
228func ext۰math۰Min(fr *frame, args []value) value {
229	return math.Min(args[0].(float64), args[1].(float64))
230}
231
232func ext۰math۰hasSSE4(fr *frame, args []value) value {
233	return false
234}
235
236func ext۰math۰hasVectorFacility(fr *frame, args []value) value {
237	return false
238}
239
240func ext۰math۰Ldexp(fr *frame, args []value) value {
241	return math.Ldexp(args[0].(float64), args[1].(int))
242}
243
244func ext۰math۰Log(fr *frame, args []value) value {
245	return math.Log(args[0].(float64))
246}
247
248func ext۰os۰runtime_args(fr *frame, args []value) value {
249	return fr.i.osArgs
250}
251
252func ext۰runtime۰Breakpoint(fr *frame, args []value) value {
253	runtime.Breakpoint()
254	return nil
255}
256
257func ext۰runtime۰Caller(fr *frame, args []value) value {
258	// func Caller(skip int) (pc uintptr, file string, line int, ok bool)
259	skip := 1 + args[0].(int)
260	for i := 0; i < skip; i++ {
261		if fr != nil {
262			fr = fr.caller
263		}
264	}
265	var pc uintptr
266	var file string
267	var line int
268	var ok bool
269	if fr != nil {
270		fn := fr.fn
271		// TODO(adonovan): use pc/posn of current instruction, not start of fn.
272		// (Required to interpret the log package's tests.)
273		pc = uintptr(unsafe.Pointer(fn))
274		posn := fn.Prog.Fset.Position(fn.Pos())
275		file = posn.Filename
276		line = posn.Line
277		ok = true
278	}
279	return tuple{pc, file, line, ok}
280}
281
282func ext۰runtime۰Callers(fr *frame, args []value) value {
283	// Callers(skip int, pc []uintptr) int
284	skip := args[0].(int)
285	pc := args[1].([]value)
286	for i := 0; i < skip; i++ {
287		if fr != nil {
288			fr = fr.caller
289		}
290	}
291	i := 0
292	for fr != nil && i < len(pc) {
293		pc[i] = uintptr(unsafe.Pointer(fr.fn))
294		i++
295		fr = fr.caller
296	}
297	return i
298}
299
300func ext۰runtime۰FuncForPC(fr *frame, args []value) value {
301	// FuncForPC(pc uintptr) *Func
302	pc := args[0].(uintptr)
303	var fn *ssa.Function
304	if pc != 0 {
305		fn = (*ssa.Function)(unsafe.Pointer(pc)) // indeed unsafe!
306	}
307	var Func value
308	Func = structure{fn} // a runtime.Func
309	return &Func
310}
311
312func ext۰runtime۰environ(fr *frame, args []value) value {
313	// This function also implements syscall.runtime_envs.
314	return environ
315}
316
317func ext۰runtime۰getgoroot(fr *frame, args []value) value {
318	return os.Getenv("GOROOT")
319}
320
321func ext۰strings۰Count(fr *frame, args []value) value {
322	// Call compiled version to avoid asm dependency.
323	return strings.Count(args[0].(string), args[1].(string))
324}
325
326func ext۰strings۰IndexByte(fr *frame, args []value) value {
327	// Call compiled version to avoid asm dependency.
328	return strings.IndexByte(args[0].(string), args[1].(byte))
329}
330
331func ext۰strings۰Index(fr *frame, args []value) value {
332	// Call compiled version to avoid asm dependency.
333	return strings.Index(args[0].(string), args[1].(string))
334}
335
336func ext۰runtime۰GOMAXPROCS(fr *frame, args []value) value {
337	// Ignore args[0]; don't let the interpreted program
338	// set the interpreter's GOMAXPROCS!
339	return runtime.GOMAXPROCS(0)
340}
341
342func ext۰runtime۰Goexit(fr *frame, args []value) value {
343	// TODO(adonovan): don't kill the interpreter's main goroutine.
344	runtime.Goexit()
345	return nil
346}
347
348func ext۰runtime۰GC(fr *frame, args []value) value {
349	runtime.GC()
350	return nil
351}
352
353func ext۰runtime۰Gosched(fr *frame, args []value) value {
354	runtime.Gosched()
355	return nil
356}
357
358func ext۰runtime۰NumCPU(fr *frame, args []value) value {
359	return runtime.NumCPU()
360}
361
362func ext۰runtime۰NumGoroutine(fr *frame, args []value) value {
363	return int(atomic.LoadInt32(&fr.i.goroutines))
364}
365
366func ext۰runtime۰ReadMemStats(fr *frame, args []value) value {
367	// TODO(adonovan): populate args[0].(Struct)
368	return nil
369}
370
371func ext۰atomic۰LoadUint32(fr *frame, args []value) value {
372	// TODO(adonovan): fix: not atomic!
373	return (*args[0].(*value)).(uint32)
374}
375
376func ext۰atomic۰StoreUint32(fr *frame, args []value) value {
377	// TODO(adonovan): fix: not atomic!
378	*args[0].(*value) = args[1].(uint32)
379	return nil
380}
381
382func ext۰atomic۰LoadInt32(fr *frame, args []value) value {
383	// TODO(adonovan): fix: not atomic!
384	return (*args[0].(*value)).(int32)
385}
386
387func ext۰atomic۰StoreInt32(fr *frame, args []value) value {
388	// TODO(adonovan): fix: not atomic!
389	*args[0].(*value) = args[1].(int32)
390	return nil
391}
392
393func ext۰atomic۰CompareAndSwapInt32(fr *frame, args []value) value {
394	// TODO(adonovan): fix: not atomic!
395	p := args[0].(*value)
396	if (*p).(int32) == args[1].(int32) {
397		*p = args[2].(int32)
398		return true
399	}
400	return false
401}
402
403func ext۰atomic۰CompareAndSwapUint32(fr *frame, args []value) value {
404	// TODO(adonovan): fix: not atomic!
405	p := args[0].(*value)
406	if (*p).(uint32) == args[1].(uint32) {
407		*p = args[2].(uint32)
408		return true
409	}
410	return false
411}
412
413func ext۰atomic۰AddInt32(fr *frame, args []value) value {
414	// TODO(adonovan): fix: not atomic!
415	p := args[0].(*value)
416	newv := (*p).(int32) + args[1].(int32)
417	*p = newv
418	return newv
419}
420
421func ext۰atomic۰AddUint32(fr *frame, args []value) value {
422	// TODO(adonovan): fix: not atomic!
423	p := args[0].(*value)
424	newv := (*p).(uint32) + args[1].(uint32)
425	*p = newv
426	return newv
427}
428
429func ext۰atomic۰LoadUint64(fr *frame, args []value) value {
430	// TODO(adonovan): fix: not atomic!
431	return (*args[0].(*value)).(uint64)
432}
433
434func ext۰atomic۰StoreUint64(fr *frame, args []value) value {
435	// TODO(adonovan): fix: not atomic!
436	*args[0].(*value) = args[1].(uint64)
437	return nil
438}
439
440func ext۰atomic۰LoadInt64(fr *frame, args []value) value {
441	// TODO(adonovan): fix: not atomic!
442	return (*args[0].(*value)).(int64)
443}
444
445func ext۰atomic۰StoreInt64(fr *frame, args []value) value {
446	// TODO(adonovan): fix: not atomic!
447	*args[0].(*value) = args[1].(int64)
448	return nil
449}
450
451func ext۰atomic۰CompareAndSwapInt64(fr *frame, args []value) value {
452	// TODO(adonovan): fix: not atomic!
453	p := args[0].(*value)
454	if (*p).(int64) == args[1].(int64) {
455		*p = args[2].(int64)
456		return true
457	}
458	return false
459}
460
461func ext۰atomic۰CompareAndSwapUint64(fr *frame, args []value) value {
462	// TODO(adonovan): fix: not atomic!
463	p := args[0].(*value)
464	if (*p).(uint64) == args[1].(uint64) {
465		*p = args[2].(uint64)
466		return true
467	}
468	return false
469}
470
471func ext۰atomic۰AddInt64(fr *frame, args []value) value {
472	// TODO(adonovan): fix: not atomic!
473	p := args[0].(*value)
474	newv := (*p).(int64) + args[1].(int64)
475	*p = newv
476	return newv
477}
478
479func ext۰atomic۰AddUint64(fr *frame, args []value) value {
480	// TODO(adonovan): fix: not atomic!
481	p := args[0].(*value)
482	newv := (*p).(uint64) + args[1].(uint64)
483	*p = newv
484	return newv
485}
486
487func ext۰atomic۰ValueLoad(fr *frame, args []value) value {
488	// TODO(adonovan): fix: not atomic!
489	// Receiver is *struct{v interface{}}.
490	return (*args[0].(*value)).(structure)[0]
491}
492
493func ext۰atomic۰ValueStore(fr *frame, args []value) value {
494	// TODO(adonovan): fix: not atomic!
495	// Receiver is *struct{v interface{}}.
496	(*args[0].(*value)).(structure)[0] = args[1]
497	return nil
498}
499
500func ext۰cpu۰cpuid(fr *frame, args []value) value {
501	return tuple{uint32(0), uint32(0), uint32(0), uint32(0)}
502}
503
504func ext۰syscall۰unix۰syscall_fcntl(fr *frame, args []value) value {
505	return tuple{int(0), wrapError(nil)}
506}
507
508// Pretend: type runtime.Func struct { entry *ssa.Function }
509
510func ext۰runtime۰Func۰FileLine(fr *frame, args []value) value {
511	// func (*runtime.Func) FileLine(uintptr) (string, int)
512	f, _ := (*args[0].(*value)).(structure)[0].(*ssa.Function)
513	pc := args[1].(uintptr)
514	_ = pc
515	if f != nil {
516		// TODO(adonovan): use position of current instruction, not fn.
517		posn := f.Prog.Fset.Position(f.Pos())
518		return tuple{posn.Filename, posn.Line}
519	}
520	return tuple{"", 0}
521}
522
523func ext۰runtime۰Func۰Name(fr *frame, args []value) value {
524	// func (*runtime.Func) Name() string
525	f, _ := (*args[0].(*value)).(structure)[0].(*ssa.Function)
526	if f != nil {
527		return f.String()
528	}
529	return ""
530}
531
532func ext۰runtime۰Func۰Entry(fr *frame, args []value) value {
533	// func (*runtime.Func) Entry() uintptr
534	f, _ := (*args[0].(*value)).(structure)[0].(*ssa.Function)
535	return uintptr(unsafe.Pointer(f))
536}
537
538func ext۰time۰now(fr *frame, args []value) value {
539	nano := time.Now().UnixNano()
540	return tuple{int64(nano / 1e9), int32(nano % 1e9), int64(0)}
541}
542
543func ext۰time۰Sleep(fr *frame, args []value) value {
544	time.Sleep(time.Duration(args[0].(int64)))
545	return nil
546}
547
548func valueToBytes(v value) []byte {
549	in := v.([]value)
550	b := make([]byte, len(in))
551	for i := range in {
552		b[i] = in[i].(byte)
553	}
554	return b
555}
556
557func ext۰testing۰MainStart(fr *frame, args []value) value {
558	// We no longer support interpretation of the "testing" package
559	// because it changes too often and uses low-level features that
560	// are a pain to emulate.
561	panic(`interpretation of the "testing" package is no longer supported`)
562}
563