]> Cypherpunks.ru repositories - gostls13.git/blob - src/runtime/runtime1.go
[dev.cc] all: merge dev.power64 (7667e41f3ced) into dev.cc
[gostls13.git] / src / runtime / runtime1.go
1 // Copyright 2009 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
5 package runtime
6
7 import "unsafe"
8
9 // Keep a cached value to make gotraceback fast,
10 // since we call it on every call to gentraceback.
11 // The cached value is a uint32 in which the low bit
12 // is the "crash" setting and the top 31 bits are the
13 // gotraceback value.
14 var traceback_cache uint32 = 2 << 1
15
16 // The GOTRACEBACK environment variable controls the
17 // behavior of a Go program that is crashing and exiting.
18 //      GOTRACEBACK=0   suppress all tracebacks
19 //      GOTRACEBACK=1   default behavior - show tracebacks but exclude runtime frames
20 //      GOTRACEBACK=2   show tracebacks including runtime frames
21 //      GOTRACEBACK=crash   show tracebacks including runtime frames, then crash (core dump etc)
22 //go:nosplit
23 func gotraceback(crash *bool) int32 {
24         _g_ := getg()
25         if crash != nil {
26                 *crash = false
27         }
28         if _g_.m.traceback != 0 {
29                 return int32(_g_.m.traceback)
30         }
31         if crash != nil {
32                 *crash = traceback_cache&1 != 0
33         }
34         return int32(traceback_cache >> 1)
35 }
36
37 var (
38         argc int32
39         argv **byte
40 )
41
42 // nosplit for use in linux/386 startup linux_setup_vdso
43 //go:nosplit
44 func argv_index(argv **byte, i int32) *byte {
45         return *(**byte)(add(unsafe.Pointer(argv), uintptr(i)*ptrSize))
46 }
47
48 func args(c int32, v **byte) {
49         argc = c
50         argv = v
51         sysargs(c, v)
52 }
53
54 var (
55         // TODO: Retire in favor of GOOS== checks.
56         isplan9   int32
57         issolaris int32
58         iswindows int32
59 )
60
61 // Information about what cpu features are available.
62 // Set on startup in asm_{x86/amd64}.s.
63 var (
64 //cpuid_ecx uint32
65 //cpuid_edx uint32
66 )
67
68 func goargs() {
69         if GOOS == "windows" {
70                 return
71         }
72
73         argslice = make([]string, argc)
74         for i := int32(0); i < argc; i++ {
75                 argslice[i] = gostringnocopy(argv_index(argv, i))
76         }
77 }
78
79 func goenvs_unix() {
80         n := int32(0)
81         for argv_index(argv, argc+1+n) != nil {
82                 n++
83         }
84
85         envs = make([]string, n)
86         for i := int32(0); i < n; i++ {
87                 envs[i] = gostringnocopy(argv_index(argv, argc+1+i))
88         }
89 }
90
91 func environ() []string {
92         return envs
93 }
94
95 func testAtomic64() {
96         var z64, x64 uint64
97
98         z64 = 42
99         x64 = 0
100         // TODO: PREFETCH((unsafe.Pointer)(&z64))
101         if cas64(&z64, x64, 1) {
102                 gothrow("cas64 failed")
103         }
104         if x64 != 0 {
105                 gothrow("cas64 failed")
106         }
107         x64 = 42
108         if !cas64(&z64, x64, 1) {
109                 gothrow("cas64 failed")
110         }
111         if x64 != 42 || z64 != 1 {
112                 gothrow("cas64 failed")
113         }
114         if atomicload64(&z64) != 1 {
115                 gothrow("load64 failed")
116         }
117         atomicstore64(&z64, (1<<40)+1)
118         if atomicload64(&z64) != (1<<40)+1 {
119                 gothrow("store64 failed")
120         }
121         if xadd64(&z64, (1<<40)+1) != (2<<40)+2 {
122                 gothrow("xadd64 failed")
123         }
124         if atomicload64(&z64) != (2<<40)+2 {
125                 gothrow("xadd64 failed")
126         }
127         if xchg64(&z64, (3<<40)+3) != (2<<40)+2 {
128                 gothrow("xchg64 failed")
129         }
130         if atomicload64(&z64) != (3<<40)+3 {
131                 gothrow("xchg64 failed")
132         }
133 }
134
135 func check() {
136         var (
137                 a     int8
138                 b     uint8
139                 c     int16
140                 d     uint16
141                 e     int32
142                 f     uint32
143                 g     int64
144                 h     uint64
145                 i, i1 float32
146                 j, j1 float64
147                 k, k1 unsafe.Pointer
148                 l     *uint16
149                 m     [4]byte
150         )
151         type x1t struct {
152                 x uint8
153         }
154         type y1t struct {
155                 x1 x1t
156                 y  uint8
157         }
158         var x1 x1t
159         var y1 y1t
160
161         if unsafe.Sizeof(a) != 1 {
162                 gothrow("bad a")
163         }
164         if unsafe.Sizeof(b) != 1 {
165                 gothrow("bad b")
166         }
167         if unsafe.Sizeof(c) != 2 {
168                 gothrow("bad c")
169         }
170         if unsafe.Sizeof(d) != 2 {
171                 gothrow("bad d")
172         }
173         if unsafe.Sizeof(e) != 4 {
174                 gothrow("bad e")
175         }
176         if unsafe.Sizeof(f) != 4 {
177                 gothrow("bad f")
178         }
179         if unsafe.Sizeof(g) != 8 {
180                 gothrow("bad g")
181         }
182         if unsafe.Sizeof(h) != 8 {
183                 gothrow("bad h")
184         }
185         if unsafe.Sizeof(i) != 4 {
186                 gothrow("bad i")
187         }
188         if unsafe.Sizeof(j) != 8 {
189                 gothrow("bad j")
190         }
191         if unsafe.Sizeof(k) != ptrSize {
192                 gothrow("bad k")
193         }
194         if unsafe.Sizeof(l) != ptrSize {
195                 gothrow("bad l")
196         }
197         if unsafe.Sizeof(x1) != 1 {
198                 gothrow("bad unsafe.Sizeof x1")
199         }
200         if unsafe.Offsetof(y1.y) != 1 {
201                 gothrow("bad offsetof y1.y")
202         }
203         if unsafe.Sizeof(y1) != 2 {
204                 gothrow("bad unsafe.Sizeof y1")
205         }
206
207         if timediv(12345*1000000000+54321, 1000000000, &e) != 12345 || e != 54321 {
208                 gothrow("bad timediv")
209         }
210
211         var z uint32
212         z = 1
213         if !cas(&z, 1, 2) {
214                 gothrow("cas1")
215         }
216         if z != 2 {
217                 gothrow("cas2")
218         }
219
220         z = 4
221         if cas(&z, 5, 6) {
222                 gothrow("cas3")
223         }
224         if z != 4 {
225                 gothrow("cas4")
226         }
227
228         z = 0xffffffff
229         if !cas(&z, 0xffffffff, 0xfffffffe) {
230                 gothrow("cas5")
231         }
232         if z != 0xfffffffe {
233                 gothrow("cas6")
234         }
235
236         k = unsafe.Pointer(uintptr(0xfedcb123))
237         if ptrSize == 8 {
238                 k = unsafe.Pointer(uintptr(unsafe.Pointer(k)) << 10)
239         }
240         if casp(&k, nil, nil) {
241                 gothrow("casp1")
242         }
243         k1 = add(k, 1)
244         if !casp(&k, k, k1) {
245                 gothrow("casp2")
246         }
247         if k != k1 {
248                 gothrow("casp3")
249         }
250
251         m = [4]byte{1, 1, 1, 1}
252         atomicor8(&m[1], 0xf0)
253         if m[0] != 1 || m[1] != 0xf1 || m[2] != 1 || m[3] != 1 {
254                 gothrow("atomicor8")
255         }
256
257         *(*uint64)(unsafe.Pointer(&j)) = ^uint64(0)
258         if j == j {
259                 gothrow("float64nan")
260         }
261         if !(j != j) {
262                 gothrow("float64nan1")
263         }
264
265         *(*uint64)(unsafe.Pointer(&j1)) = ^uint64(1)
266         if j == j1 {
267                 gothrow("float64nan2")
268         }
269         if !(j != j1) {
270                 gothrow("float64nan3")
271         }
272
273         *(*uint32)(unsafe.Pointer(&i)) = ^uint32(0)
274         if i == i {
275                 gothrow("float32nan")
276         }
277         if i == i {
278                 gothrow("float32nan1")
279         }
280
281         *(*uint32)(unsafe.Pointer(&i1)) = ^uint32(1)
282         if i == i1 {
283                 gothrow("float32nan2")
284         }
285         if i == i1 {
286                 gothrow("float32nan3")
287         }
288
289         testAtomic64()
290
291         if _FixedStack != round2(_FixedStack) {
292                 gothrow("FixedStack is not power-of-2")
293         }
294 }
295
296 type dbgVar struct {
297         name  string
298         value *int32
299 }
300
301 // Do we report invalid pointers found during stack or heap scans?
302 //var invalidptr int32 = 1
303
304 var dbgvars = []dbgVar{
305         {"allocfreetrace", &debug.allocfreetrace},
306         {"invalidptr", &invalidptr},
307         {"efence", &debug.efence},
308         {"gctrace", &debug.gctrace},
309         {"gcdead", &debug.gcdead},
310         {"scheddetail", &debug.scheddetail},
311         {"schedtrace", &debug.schedtrace},
312         {"scavenge", &debug.scavenge},
313 }
314
315 func parsedebugvars() {
316         for p := gogetenv("GODEBUG"); p != ""; {
317                 field := ""
318                 i := index(p, ",")
319                 if i < 0 {
320                         field, p = p, ""
321                 } else {
322                         field, p = p[:i], p[i+1:]
323                 }
324                 i = index(field, "=")
325                 if i < 0 {
326                         continue
327                 }
328                 key, value := field[:i], field[i+1:]
329                 for _, v := range dbgvars {
330                         if v.name == key {
331                                 *v.value = int32(goatoi(value))
332                         }
333                 }
334         }
335
336         switch p := gogetenv("GOTRACEBACK"); p {
337         case "":
338                 traceback_cache = 1 << 1
339         case "crash":
340                 traceback_cache = 2<<1 | 1
341         default:
342                 traceback_cache = uint32(goatoi(p)) << 1
343         }
344 }
345
346 // Poor mans 64-bit division.
347 // This is a very special function, do not use it if you are not sure what you are doing.
348 // int64 division is lowered into _divv() call on 386, which does not fit into nosplit functions.
349 // Handles overflow in a time-specific manner.
350 //go:nosplit
351 func timediv(v int64, div int32, rem *int32) int32 {
352         res := int32(0)
353         for bit := 30; bit >= 0; bit-- {
354                 if v >= int64(div)<<uint(bit) {
355                         v = v - (int64(div) << uint(bit))
356                         res += 1 << uint(bit)
357                 }
358         }
359         if v >= int64(div) {
360                 if rem != nil {
361                         *rem = 0
362                 }
363                 return 0x7fffffff
364         }
365         if rem != nil {
366                 *rem = int32(v)
367         }
368         return res
369 }
370
371 // Helpers for Go. Must be NOSPLIT, must only call NOSPLIT functions, and must not block.
372
373 //go:nosplit
374 func acquirem() *m {
375         _g_ := getg()
376         _g_.m.locks++
377         return _g_.m
378 }
379
380 //go:nosplit
381 func releasem(mp *m) {
382         _g_ := getg()
383         mp.locks--
384         if mp.locks == 0 && _g_.preempt {
385                 // restore the preemption request in case we've cleared it in newstack
386                 _g_.stackguard0 = stackPreempt
387         }
388 }
389
390 //go:nosplit
391 func gomcache() *mcache {
392         return getg().m.mcache
393 }
394
395 var typelink, etypelink [0]byte
396
397 //go:nosplit
398 func typelinks() []*_type {
399         var ret []*_type
400         sp := (*slice)(unsafe.Pointer(&ret))
401         sp.array = (*byte)(unsafe.Pointer(&typelink))
402         sp.len = uint((uintptr(unsafe.Pointer(&etypelink)) - uintptr(unsafe.Pointer(&typelink))) / unsafe.Sizeof(ret[0]))
403         sp.cap = sp.len
404         return ret
405 }
406
407 // TODO: move back into mgc0.c when converted to Go
408 func readgogc() int32 {
409         p := gogetenv("GOGC")
410         if p == "" {
411                 return 100
412         }
413         if p == "off" {
414                 return -1
415         }
416         return int32(goatoi(p))
417 }